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