Compare commits
7
Commits
8abe1d1bc2
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
54c7502f0f | ||
|
|
eb374d20f5 | ||
|
|
57f4f9f165 | ||
|
|
f016950ac7 | ||
|
|
f4dab3e354 | ||
|
|
6b49db5801 | ||
|
|
b0457388dc |
+10
@@ -1,6 +1,8 @@
|
|||||||
dist-newstyle
|
dist-newstyle
|
||||||
dist-newstyle
|
dist-newstyle
|
||||||
/.stack-work/
|
/.stack-work/
|
||||||
|
/.stack-root/
|
||||||
|
/.cabal-config/
|
||||||
*.mmd
|
*.mmd
|
||||||
*.png
|
*.png
|
||||||
*.svg
|
*.svg
|
||||||
@@ -10,3 +12,11 @@ dist-newstyle
|
|||||||
dist-newstyle
|
dist-newstyle
|
||||||
output/
|
output/
|
||||||
*.log
|
*.log
|
||||||
|
cabal.project
|
||||||
|
lts-24-34.yaml
|
||||||
|
stack-setup-2.yaml
|
||||||
|
analytics-charts.md
|
||||||
|
architecture-deep-dive.md
|
||||||
|
devcontainer.org
|
||||||
|
.devcontainer/
|
||||||
|
root.json
|
||||||
|
|||||||
@@ -6,8 +6,9 @@ A self-contained CLI tool that converts Markdown with Mermaid diagrams into PDF
|
|||||||
|
|
||||||
docster -pdf path/to/file.md
|
docster -pdf path/to/file.md
|
||||||
docster -html path/to/file.md
|
docster -html path/to/file.md
|
||||||
|
docster -docx path/to/file.md
|
||||||
|
|
||||||
Mermaid code blocks (```mermaid) will be rendered to SVG and embedded.
|
Mermaid code blocks (```mermaid) will be rendered to SVG (HTML) or PNG (PDF/DOCX) and embedded.
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
|
|||||||
+4
-4
@@ -1,9 +1,9 @@
|
|||||||
cabal-version: 3.0
|
cabal-version: 3.0
|
||||||
name: docster
|
name: docster
|
||||||
version: 0.1.0.0
|
version: 0.1.0.0
|
||||||
synopsis: A self-contained CLI tool that converts Markdown with Mermaid diagrams to PDF/HTML
|
synopsis: A self-contained CLI tool that converts Markdown with Mermaid diagrams to PDF, HTML, or DOCX
|
||||||
description: Docster converts Markdown documents containing Mermaid diagrams into PDF or HTML files
|
description: Docster converts Markdown documents containing Mermaid diagrams into PDF, HTML, or DOCX files
|
||||||
using Pandoc and Mermaid CLI. It automatically renders Mermaid code blocks to SVG
|
using Pandoc and Mermaid CLI. It automatically renders Mermaid code blocks to SVG (HTML) or PNG (PDF/DOCX)
|
||||||
and embeds them in the output.
|
and embeds them in the output.
|
||||||
homepage: https://github.com/yourusername/docster
|
homepage: https://github.com/yourusername/docster
|
||||||
license: BSD-3-Clause
|
license: BSD-3-Clause
|
||||||
@@ -41,7 +41,7 @@ library
|
|||||||
process >=1.6 && <1.7,
|
process >=1.6 && <1.7,
|
||||||
hashable >=1.4 && <1.6,
|
hashable >=1.4 && <1.6,
|
||||||
containers >=0.6 && <0.8,
|
containers >=0.6 && <0.8,
|
||||||
pandoc >=3.0 && <3.2,
|
pandoc >=3.0 && <3.8,
|
||||||
pandoc-types >=1.23 && <1.25,
|
pandoc-types >=1.23 && <1.25,
|
||||||
bytestring >=0.11 && <0.13,
|
bytestring >=0.11 && <0.13,
|
||||||
temporary >=1.3 && <1.4,
|
temporary >=1.3 && <1.4,
|
||||||
|
|||||||
+44
-72
@@ -1,7 +1,7 @@
|
|||||||
{-# LANGUAGE OverloadedStrings #-}
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
{-# LANGUAGE LambdaCase #-}
|
{-# LANGUAGE LambdaCase #-}
|
||||||
|
|
||||||
-- | Document compilation functionality for PDF and HTML output
|
-- | Document compilation functionality for PDF, HTML, and DOCX output
|
||||||
module Docster.Compiler
|
module Docster.Compiler
|
||||||
( -- * Compilation Functions
|
( -- * Compilation Functions
|
||||||
compileToPDF
|
compileToPDF
|
||||||
@@ -47,7 +47,6 @@ data CompilationContext = CompilationContext
|
|||||||
, ccDocName :: Text
|
, ccDocName :: Text
|
||||||
, ccReaderOptions :: ReaderOptions
|
, ccReaderOptions :: ReaderOptions
|
||||||
, ccConfig :: DiagramConfig
|
, ccConfig :: DiagramConfig
|
||||||
, ccWritesFile :: Bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
-- | Monad stack for compilation pipeline
|
-- | Monad stack for compilation pipeline
|
||||||
@@ -57,44 +56,57 @@ type CompilationM = ReaderT CompilationContext (ExceptT DocsterError IO)
|
|||||||
data CompilationStrategy = CompilationStrategy
|
data CompilationStrategy = CompilationStrategy
|
||||||
{ -- | Format for diagram configuration
|
{ -- | Format for diagram configuration
|
||||||
csOutputFormat :: OutputFormat
|
csOutputFormat :: OutputFormat
|
||||||
-- | Pandoc writer function (returns Text for HTML/PDF, unused for DOCX)
|
-- | Pandoc writer: writes output directly to the given file path
|
||||||
, csWriter :: WriterOptions -> Pandoc -> PandocIO Text
|
, csWriter :: WriterOptions -> Pandoc -> FilePath -> IO (Either DocsterError ())
|
||||||
-- | Post-processing function for the generated content
|
-- | Post-processing after write (PDF→xelatex, HTML→open browser, DOCX→noop)
|
||||||
, csProcessOutput :: String -> Text -> IO (Either DocsterError ())
|
, csPostProcess :: String -> IO (Either DocsterError ())
|
||||||
-- | Success message formatter
|
-- | Success message formatter
|
||||||
, csSuccessMessage :: String -> Text
|
, csSuccessMessage :: String -> Text
|
||||||
-- | True for formats where writer writes a file directly (DOCX)
|
|
||||||
, csWritesFile :: Bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
-- | PDF compilation strategy
|
-- | PDF compilation strategy
|
||||||
pdfStrategy :: CompilationStrategy
|
pdfStrategy :: CompilationStrategy
|
||||||
pdfStrategy = CompilationStrategy
|
pdfStrategy = CompilationStrategy
|
||||||
{ csOutputFormat = PDF
|
{ csOutputFormat = PDF
|
||||||
, csWriter = writeLaTeX
|
, csWriter = \opts doc path -> do
|
||||||
, csProcessOutput = processPDFOutput
|
result <- runIO (writeLaTeX opts doc)
|
||||||
|
case result of
|
||||||
|
Left err -> return $ Left $ FileError $ "LaTeX write failed: " <> T.pack (show err)
|
||||||
|
Right latex -> do
|
||||||
|
TIO.writeFile path (latexTemplate latex)
|
||||||
|
return $ Right ()
|
||||||
|
, csPostProcess = processPDFOutput
|
||||||
, csSuccessMessage = \path -> successEmoji <> " PDF written to " <> T.pack path
|
, csSuccessMessage = \path -> successEmoji <> " PDF written to " <> T.pack path
|
||||||
, csWritesFile = False
|
|
||||||
}
|
}
|
||||||
|
|
||||||
-- | HTML compilation strategy
|
-- | HTML compilation strategy
|
||||||
htmlStrategy :: CompilationStrategy
|
htmlStrategy :: CompilationStrategy
|
||||||
htmlStrategy = CompilationStrategy
|
htmlStrategy = CompilationStrategy
|
||||||
{ csOutputFormat = HTML
|
{ csOutputFormat = HTML
|
||||||
, csWriter = writeHtml5String
|
, csWriter = \opts doc path -> do
|
||||||
, csProcessOutput = processHTMLOutput
|
result <- runIO (writeHtml5String opts doc)
|
||||||
|
case result of
|
||||||
|
Left err -> return $ Left $ FileError $ "HTML write failed: " <> T.pack (show err)
|
||||||
|
Right html -> do
|
||||||
|
TIO.writeFile path html
|
||||||
|
return $ Right ()
|
||||||
|
, csPostProcess = processHTMLOutput
|
||||||
, csSuccessMessage = \path -> successEmoji <> " HTML written to " <> T.pack path
|
, csSuccessMessage = \path -> successEmoji <> " HTML written to " <> T.pack path
|
||||||
, csWritesFile = False
|
|
||||||
}
|
}
|
||||||
|
|
||||||
-- | DOCX compilation strategy (Pandoc writes file directly)
|
-- | DOCX compilation strategy (Pandoc writes file directly)
|
||||||
docxStrategy :: CompilationStrategy
|
docxStrategy :: CompilationStrategy
|
||||||
docxStrategy = CompilationStrategy
|
docxStrategy = CompilationStrategy
|
||||||
{ csOutputFormat = DOCX
|
{ csOutputFormat = DOCX
|
||||||
, csWriter = \_ _ -> return "" -- unused: writeDocx writes file directly
|
, csWriter = \opts doc path -> do
|
||||||
, csProcessOutput = \_ _ -> return $ Right () -- no post-processing needed
|
result <- runIO (writeDocx opts doc)
|
||||||
|
case result of
|
||||||
|
Left err -> return $ Left $ FileError $ "DOCX generation failed: " <> T.pack (show err)
|
||||||
|
Right docxBS -> do
|
||||||
|
BSL.writeFile path docxBS
|
||||||
|
return $ Right ()
|
||||||
|
, csPostProcess = \_ -> return $ Right () -- no post-processing needed
|
||||||
, csSuccessMessage = \path -> successEmoji <> " DOCX written to " <> T.pack path
|
, csSuccessMessage = \path -> successEmoji <> " DOCX written to " <> T.pack path
|
||||||
, csWritesFile = True
|
|
||||||
}
|
}
|
||||||
|
|
||||||
-- | Parse LaTeX log content to extract meaningful error messages
|
-- | Parse LaTeX log content to extract meaningful error messages
|
||||||
@@ -160,11 +172,10 @@ extractFatalErrors = mapMaybe extractFatal
|
|||||||
| "! " `T.isPrefixOf` line && not ("Missing character:" `T.isInfixOf` line) = Just $ T.drop 2 line
|
| "! " `T.isPrefixOf` line && not ("Missing character:" `T.isInfixOf` line) = Just $ T.drop 2 line
|
||||||
| otherwise = Nothing
|
| otherwise = Nothing
|
||||||
|
|
||||||
-- | Process PDF output: LaTeX template application and direct XeLaTeX compilation
|
-- | Process PDF output: direct XeLaTeX compilation (LaTeX already written by csWriter)
|
||||||
processPDFOutput :: String -> Text -> IO (Either DocsterError ())
|
processPDFOutput :: String -> IO (Either DocsterError ())
|
||||||
processPDFOutput outputPath latexOutput = do
|
processPDFOutput outputPath = do
|
||||||
let completeLatex = latexTemplate latexOutput
|
let logOutputPath = replaceExtension outputPath "log"
|
||||||
logOutputPath = replaceExtension outputPath "log"
|
|
||||||
|
|
||||||
-- Use temporary directory for LaTeX compilation
|
-- Use temporary directory for LaTeX compilation
|
||||||
withSystemTempDirectory "docster-latex" $ \tempDir -> do
|
withSystemTempDirectory "docster-latex" $ \tempDir -> do
|
||||||
@@ -172,9 +183,6 @@ processPDFOutput outputPath latexOutput = do
|
|||||||
pdfFile = tempDir </> "document.pdf"
|
pdfFile = tempDir </> "document.pdf"
|
||||||
logFile = tempDir </> "document.log"
|
logFile = tempDir </> "document.log"
|
||||||
|
|
||||||
-- Write LaTeX content to temporary file
|
|
||||||
TIO.writeFile texFile completeLatex
|
|
||||||
|
|
||||||
-- Run XeLaTeX compilation
|
-- Run XeLaTeX compilation
|
||||||
(exitCode, _stdout, stderr) <- readProcessWithExitCode "xelatex"
|
(exitCode, _stdout, stderr) <- readProcessWithExitCode "xelatex"
|
||||||
[ "-output-directory=" <> tempDir
|
[ "-output-directory=" <> tempDir
|
||||||
@@ -210,11 +218,9 @@ processPDFOutput outputPath latexOutput = do
|
|||||||
errorSummary <> "\n\n" <>
|
errorSummary <> "\n\n" <>
|
||||||
"Full LaTeX log written to: " <> T.pack logOutputPath
|
"Full LaTeX log written to: " <> T.pack logOutputPath
|
||||||
|
|
||||||
-- | Process HTML output: file writing and browser opening
|
-- | Process HTML output: open browser (HTML already written by csWriter)
|
||||||
processHTMLOutput :: String -> Text -> IO (Either DocsterError ())
|
processHTMLOutput :: String -> IO (Either DocsterError ())
|
||||||
processHTMLOutput outputPath html = do
|
processHTMLOutput outputPath = do
|
||||||
TIO.writeFile outputPath html
|
|
||||||
|
|
||||||
-- Open the generated HTML file in browser for verification
|
-- Open the generated HTML file in browser for verification
|
||||||
putStrLn $ "🌐 Opening " <> outputPath <> " in browser for error checking..."
|
putStrLn $ "🌐 Opening " <> outputPath <> " in browser for error checking..."
|
||||||
void $ callProcess "open" [outputPath]
|
void $ callProcess "open" [outputPath]
|
||||||
@@ -267,28 +273,13 @@ transformDocumentM pandoc = do
|
|||||||
docName <- asks ccDocName
|
docName <- asks ccDocName
|
||||||
liftEitherM $ transformDocument config docName pandoc
|
liftEitherM $ transformDocument config docName pandoc
|
||||||
|
|
||||||
-- | Pipeline step: Generate output using format-specific writer
|
-- | Pipeline step: Write output and post-process (format-specific)
|
||||||
generateOutputM :: Pandoc -> CompilationM Text
|
writeAndProcessOutput :: Pandoc -> CompilationM ()
|
||||||
generateOutputM pandoc = do
|
writeAndProcessOutput pandoc = do
|
||||||
strategy <- asks ccStrategy
|
strategy <- asks ccStrategy
|
||||||
writesFile <- asks ccWritesFile
|
outputPath <- asks ccOutputPath
|
||||||
if writesFile
|
liftEitherM $ csWriter strategy def pandoc outputPath
|
||||||
then do
|
liftEitherM $ (csPostProcess strategy) outputPath
|
||||||
outputPath <- asks ccOutputPath
|
|
||||||
_ <- liftIO $ generateOutputFile strategy outputPath pandoc
|
|
||||||
return "" -- placeholder, won't be used
|
|
||||||
else liftEitherM $ generateOutput strategy pandoc
|
|
||||||
|
|
||||||
-- | Pipeline step: Process output and write to file
|
|
||||||
processOutput :: Text -> CompilationM ()
|
|
||||||
processOutput output = do
|
|
||||||
strategy <- asks ccStrategy
|
|
||||||
writesFile <- asks ccWritesFile
|
|
||||||
if writesFile
|
|
||||||
then return () -- file already written by writer
|
|
||||||
else do
|
|
||||||
outputPath <- asks ccOutputPath
|
|
||||||
liftEitherM $ csProcessOutput strategy outputPath output
|
|
||||||
|
|
||||||
-- | Pipeline step: Print success message
|
-- | Pipeline step: Print success message
|
||||||
printSuccess :: CompilationM ()
|
printSuccess :: CompilationM ()
|
||||||
@@ -302,8 +293,8 @@ compileWithStrategy :: CompilationStrategy -> SourceDir -> OutputDir -> Text ->
|
|||||||
compileWithStrategy strategy sourceDir outputDir docName (OutputPath inputPath) (OutputPath outputPath) = do
|
compileWithStrategy strategy sourceDir outputDir docName (OutputPath inputPath) (OutputPath outputPath) = do
|
||||||
let readerOptions = def { readerExtensions = getDefaultExtensions "markdown" }
|
let readerOptions = def { readerExtensions = getDefaultExtensions "markdown" }
|
||||||
config = DiagramConfig sourceDir outputDir (csOutputFormat strategy)
|
config = DiagramConfig sourceDir outputDir (csOutputFormat strategy)
|
||||||
context = CompilationContext strategy inputPath outputPath docName readerOptions config (csWritesFile strategy)
|
context = CompilationContext strategy inputPath outputPath docName readerOptions config
|
||||||
pipeline = readContent >>= parseDocument >>= transformDocumentM >>= generateOutputM >>= processOutput >> printSuccess
|
pipeline = readContent >>= parseDocument >>= transformDocumentM >>= writeAndProcessOutput >> printSuccess
|
||||||
|
|
||||||
runExceptT $ runReaderT pipeline context
|
runExceptT $ runReaderT pipeline context
|
||||||
|
|
||||||
@@ -315,26 +306,7 @@ parseMarkdown readerOptions content = do
|
|||||||
Left err -> Left $ FileError $ "Failed to parse markdown: " <> T.pack (show err)
|
Left err -> Left $ FileError $ "Failed to parse markdown: " <> T.pack (show err)
|
||||||
Right pandoc -> Right pandoc
|
Right pandoc -> Right pandoc
|
||||||
|
|
||||||
-- | Generate output using the strategy's writer with error handling
|
|
||||||
generateOutput :: CompilationStrategy -> Pandoc -> IO (Either DocsterError Text)
|
|
||||||
generateOutput strategy transformed = do
|
|
||||||
result <- runIO $ csWriter strategy def transformed
|
|
||||||
return $ case result of
|
|
||||||
Left err -> Left $ case csOutputFormat strategy of
|
|
||||||
PDF -> PDFGenerationError $ "LaTeX generation failed: " <> T.pack (show err)
|
|
||||||
HTML -> FileError $ "HTML generation failed: " <> T.pack (show err)
|
|
||||||
DOCX -> FileError $ "DOCX generation failed: " <> T.pack (show err)
|
|
||||||
Right output -> Right output
|
|
||||||
|
|
||||||
-- | Generate output file directly (for DOCX which writes to file)
|
|
||||||
generateOutputFile :: CompilationStrategy -> FilePath -> Pandoc -> IO (Either DocsterError ())
|
|
||||||
generateOutputFile _ outputPath pandoc = do
|
|
||||||
result <- runIO $ writeDocx def pandoc
|
|
||||||
case result of
|
|
||||||
Left err -> return $ Left $ FileError $ "DOCX generation failed: " <> T.pack (show err)
|
|
||||||
Right docxBS -> do
|
|
||||||
BSL.writeFile outputPath docxBS
|
|
||||||
return $ Right ()
|
|
||||||
|
|
||||||
-- | Compile markdown to PDF using XeLaTeX
|
-- | Compile markdown to PDF using XeLaTeX
|
||||||
compileToPDF :: FilePath -> IO ()
|
compileToPDF :: FilePath -> IO ()
|
||||||
|
|||||||
@@ -79,6 +79,8 @@ generateDiagramPaths (DiagramConfig _ (OutputDir outDir) format) (DiagramId diag
|
|||||||
in (svgFile, T.pack $ takeFileName svgFile)
|
in (svgFile, T.pack $ takeFileName svgFile)
|
||||||
PDF -> let pngFile = outDir </> diagIdStr <> ".png"
|
PDF -> let pngFile = outDir </> diagIdStr <> ".png"
|
||||||
in (pngFile, T.pack pngFile)
|
in (pngFile, T.pack pngFile)
|
||||||
|
DOCX -> let pngFile = outDir </> diagIdStr <> ".png"
|
||||||
|
in (pngFile, T.pack pngFile)
|
||||||
|
|
||||||
-- | Puppeteer configuration content for disabling sandbox
|
-- | Puppeteer configuration content for disabling sandbox
|
||||||
puppeteerConfigContent :: Text
|
puppeteerConfigContent :: Text
|
||||||
@@ -90,6 +92,7 @@ callMermaidProcess format mmdFile outputFile = do
|
|||||||
let baseArgs = case format of
|
let baseArgs = case format of
|
||||||
HTML -> ["-i", mmdFile, "-o", outputFile]
|
HTML -> ["-i", mmdFile, "-o", outputFile]
|
||||||
PDF -> ["-i", mmdFile, "-o", outputFile, "--scale", "3"]
|
PDF -> ["-i", mmdFile, "-o", outputFile, "--scale", "3"]
|
||||||
|
DOCX -> ["-i", mmdFile, "-o", outputFile]
|
||||||
|
|
||||||
-- Create temporary puppeteer config file
|
-- Create temporary puppeteer config file
|
||||||
result <- bracket
|
result <- bracket
|
||||||
|
|||||||
@@ -36,8 +36,9 @@ transformDocument config docName (Pandoc meta blocks) = do
|
|||||||
Left err -> return $ Left err
|
Left err -> return $ Left err
|
||||||
Right (newBlocks, _finalState) ->
|
Right (newBlocks, _finalState) ->
|
||||||
case dcOutputFormat config of
|
case dcOutputFormat config of
|
||||||
PDF -> return $ Right $ substituteUnicodeSymbols (Pandoc meta newBlocks)
|
PDF -> return $ Right $ substituteUnicodeSymbols (Pandoc meta newBlocks)
|
||||||
HTML -> return $ Right $ Pandoc meta newBlocks
|
HTML -> return $ Right $ Pandoc meta newBlocks
|
||||||
|
DOCX -> return $ Right $ Pandoc meta newBlocks
|
||||||
|
|
||||||
-- | Process a single block with heading tracking state
|
-- | Process a single block with heading tracking state
|
||||||
processBlockStateful :: DiagramConfig -> Block -> TransformM Block
|
processBlockStateful :: DiagramConfig -> Block -> TransformM Block
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ module Docster.TransformSpec (spec) where
|
|||||||
|
|
||||||
import Test.Hspec
|
import Test.Hspec
|
||||||
import qualified Data.Map.Strict as Map
|
import qualified Data.Map.Strict as Map
|
||||||
import Data.Text (Text)
|
import Data.Text()
|
||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
import Text.Pandoc.Definition (Inline(..))
|
import Text.Pandoc.Definition (Inline(..))
|
||||||
|
|
||||||
@@ -64,21 +64,21 @@ spec = do
|
|||||||
describe "diagram naming logic" $ do
|
describe "diagram naming logic" $ do
|
||||||
it "first diagram under heading has no suffix" $
|
it "first diagram under heading has no suffix" $
|
||||||
let baseName = "file_flow"
|
let baseName = "file_flow"
|
||||||
counter = Map.findWithDefault 0 baseName Map.empty
|
counter = Map.findWithDefault (0 :: Int) baseName Map.empty
|
||||||
diagName = if counter == 0 then baseName else baseName <> "_" <> T.pack (show counter)
|
diagName = if counter == 0 then baseName else baseName <> "_" <> T.pack (show counter)
|
||||||
in diagName `shouldBe` "file_flow"
|
in diagName `shouldBe` "file_flow"
|
||||||
|
|
||||||
it "second diagram gets _1 suffix" $
|
it "second diagram gets _1 suffix" $
|
||||||
let baseName = "file_flow"
|
let baseName = "file_flow"
|
||||||
counters = Map.singleton "file_flow" 1
|
counters = Map.singleton "file_flow" (1 :: Int)
|
||||||
counter = Map.findWithDefault 0 baseName counters
|
counter = Map.findWithDefault (0 :: Int) baseName counters
|
||||||
diagName = if counter == 0 then baseName else baseName <> "_" <> T.pack (show counter)
|
diagName = if counter == 0 then baseName else baseName <> "_" <> T.pack (show counter)
|
||||||
in diagName `shouldBe` "file_flow_1"
|
in diagName `shouldBe` "file_flow_1"
|
||||||
|
|
||||||
it "third diagram gets _2 suffix" $
|
it "third diagram gets _2 suffix" $
|
||||||
let baseName = "file_flow"
|
let baseName = "file_flow"
|
||||||
counters = Map.singleton "file_flow" 2
|
counters = Map.singleton "file_flow" (2 :: Int)
|
||||||
counter = Map.findWithDefault 0 baseName counters
|
counter = Map.findWithDefault (0 :: Int) baseName counters
|
||||||
diagName = if counter == 0 then baseName else baseName <> "_" <> T.pack (show counter)
|
diagName = if counter == 0 then baseName else baseName <> "_" <> T.pack (show counter)
|
||||||
in diagName `shouldBe` "file_flow_2"
|
in diagName `shouldBe` "file_flow_2"
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user