Fix broken diagram links by implementing format-aware image paths

Problem: HTML output contained broken image links because all formats
used the same full path (e.g., living-documentation/diagram-536389.png).
This worked for PDFs but failed for HTML since both files are in the
same directory and need relative paths.

Solution:
- Add output format detection with isHTMLOutput function
- Update processMermaidBlock to take OutputPath parameter
- Generate context-appropriate paths:
  * HTML: relative path (diagram-536389.png)
  * PDF: full path (living-documentation/diagram-536389.png)
- Update transformDocument and compilation functions to pass output path

Both HTML and PDF generation now work correctly with proper image embedding.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Willem van den Ende 2025-07-29 19:06:14 +02:00
parent 1a92427b90
commit 4aab281f4b

View File

@ -9,7 +9,7 @@ import Text.Pandoc.PDF (makePDF)
import Text.Pandoc.Walk (walkM)
import Text.Pandoc.Extensions (getDefaultExtensions)
import System.Environment (getArgs)
import System.FilePath (replaceExtension, takeDirectory, (</>))
import System.FilePath (replaceExtension, takeDirectory, takeFileName, takeExtension, (</>))
import System.Process (callProcess)
import System.Directory (removeFile)
import Data.Text (Text)
@ -52,13 +52,17 @@ generateDiagramId explicitId contents
| otherwise = DiagramId explicitId
-- | Transform Mermaid code blocks into image embeds with resource cleanup
processMermaidBlock :: SourceDir -> Block -> IO Block
processMermaidBlock (SourceDir sourceDir) (CodeBlock (id', classes, _) contents)
processMermaidBlock :: SourceDir -> OutputPath -> Block -> IO Block
processMermaidBlock (SourceDir sourceDir) (OutputPath outputPath) (CodeBlock (id', classes, _) contents)
| "mermaid" `elem` classes = do
let DiagramId diagId = generateDiagramId id' contents
diagIdStr = T.unpack diagId
mmdFile = sourceDir </> diagIdStr <> ".mmd"
pngFile = sourceDir </> diagIdStr <> ".png"
-- Determine the correct image path based on output format
imagePath = if isHTMLOutput outputPath
then takeFileName pngFile -- Just filename for HTML
else pngFile -- Full path for PDF/LaTeX
-- Use bracket to ensure cleanup of temporary mermaid file
bracket
@ -67,12 +71,16 @@ processMermaidBlock (SourceDir sourceDir) (CodeBlock (id', classes, _) contents)
(\_ -> do
void $ callProcess mermaidCommand ["-i", mmdFile, "-o", pngFile]
putStrLn $ successEmoji <> " Generated " <> pngFile
return $ Para [Image nullAttr [] (T.pack pngFile, "Mermaid diagram")])
processMermaidBlock _ block = return block
return $ Para [Image nullAttr [] (T.pack imagePath, "Mermaid diagram")])
processMermaidBlock _ _ block = return block
-- | Check if output is HTML format based on file extension
isHTMLOutput :: FilePath -> Bool
isHTMLOutput path = takeExtension path == ".html"
-- | Walk the Pandoc AST and process blocks using walkM
transformDocument :: SourceDir -> Pandoc -> IO Pandoc
transformDocument sourceDir = walkM (processMermaidBlock sourceDir)
transformDocument :: SourceDir -> OutputPath -> Pandoc -> IO Pandoc
transformDocument sourceDir outputPath = walkM (processMermaidBlock sourceDir outputPath)
-- | LaTeX template with comprehensive package support
latexTemplate :: Text -> Text
@ -154,12 +162,12 @@ compileToPDF path = do
-- | Safe PDF compilation with proper error handling
compileToPDFSafe :: SourceDir -> OutputPath -> OutputPath -> IO (Either DocsterError ())
compileToPDFSafe sourceDir (OutputPath inputPath) (OutputPath outputPath) = do
compileToPDFSafe sourceDir (OutputPath inputPath) outputPath@(OutputPath outputPathStr) = do
content <- TIO.readFile inputPath
let readerOptions = def { readerExtensions = getDefaultExtensions "markdown" }
pandoc <- runIOorExplode $ readMarkdown readerOptions content
transformed <- transformDocument sourceDir pandoc
transformed <- transformDocument sourceDir outputPath pandoc
-- Generate LaTeX with proper template
latexOutput <- runIOorExplode $ writeLaTeX def transformed
@ -169,8 +177,8 @@ compileToPDFSafe sourceDir (OutputPath inputPath) (OutputPath outputPath) = do
case result of
Left err -> return $ Left $ PDFGenerationError $ T.pack $ show err
Right bs -> do
BL.writeFile outputPath bs
putStrLn $ successEmoji <> " PDF written to " <> outputPath
BL.writeFile outputPathStr bs
putStrLn $ successEmoji <> " PDF written to " <> outputPathStr
return $ Right ()
-- | Compile markdown to HTML
@ -186,20 +194,20 @@ compileToHTML path = do
-- | Safe HTML compilation with proper error handling
compileToHTMLSafe :: SourceDir -> OutputPath -> OutputPath -> IO (Either DocsterError ())
compileToHTMLSafe sourceDir (OutputPath inputPath) (OutputPath outputPath) = do
compileToHTMLSafe sourceDir (OutputPath inputPath) outputPath@(OutputPath outputPathStr) = do
content <- TIO.readFile inputPath
let readerOptions = def { readerExtensions = getDefaultExtensions "markdown" }
pandoc <- runIOorExplode $ readMarkdown readerOptions content
transformed <- transformDocument sourceDir pandoc
transformed <- transformDocument sourceDir outputPath pandoc
html <- runIOorExplode $ writeHtml5String def transformed
TIO.writeFile outputPath html
putStrLn $ successEmoji <> " HTML written to " <> outputPath
TIO.writeFile outputPathStr html
putStrLn $ successEmoji <> " HTML written to " <> outputPathStr
-- Open the generated HTML file in browser
putStrLn $ "🌐 Opening " <> outputPath <> " in browser for error checking..."
void $ callProcess "open" [outputPath]
putStrLn $ "🌐 Opening " <> outputPathStr <> " in browser for error checking..."
void $ callProcess "open" [outputPathStr]
return $ Right ()