109 lines
3.1 KiB
Haskell
109 lines
3.1 KiB
Haskell
{-# LANGUAGE OverloadedStrings #-}
|
|
|
|
-- | Core types and error definitions for Docster
|
|
module Docster.Types
|
|
( -- * Error Types
|
|
DocsterError(..)
|
|
|
|
-- * Output Format
|
|
, OutputFormat(..)
|
|
|
|
-- * Domain Types
|
|
, SourceDir(..)
|
|
, OutputDir(..)
|
|
, OutputPath(..)
|
|
, DiagramId(..)
|
|
, DiagramConfig(..)
|
|
|
|
-- * Traversal State
|
|
, TraversalState(..)
|
|
, initialTraversalState
|
|
, normalizeHeading
|
|
|
|
-- * Path Utilities
|
|
, computeOutputDir
|
|
, ensureOutputDir
|
|
) where
|
|
|
|
import Data.Text (Text)
|
|
import qualified Data.Text as T
|
|
import Data.Char (isAlphaNum, isSpace)
|
|
import Data.Map.Strict (Map)
|
|
import qualified Data.Map.Strict as Map
|
|
import Control.Exception (Exception)
|
|
import System.FilePath (takeDirectory, takeBaseName, (</>))
|
|
import System.Directory (createDirectoryIfMissing)
|
|
|
|
-- | Custom error types for comprehensive error handling
|
|
data DocsterError
|
|
= InvalidUsage Text
|
|
| FileError Text
|
|
| PDFGenerationError Text
|
|
| ProcessError Text
|
|
deriving (Show)
|
|
|
|
instance Exception DocsterError
|
|
|
|
-- | Output format for document generation
|
|
data OutputFormat = PDF | HTML | DOCX
|
|
deriving (Show, Eq)
|
|
|
|
-- | Type-safe wrapper for source directory paths
|
|
newtype SourceDir = SourceDir FilePath
|
|
deriving (Show, Eq)
|
|
|
|
-- | Type-safe wrapper for output directory paths
|
|
newtype OutputDir = OutputDir FilePath
|
|
deriving (Show, Eq)
|
|
|
|
-- | Type-safe wrapper for output file paths
|
|
newtype OutputPath = OutputPath FilePath
|
|
deriving (Show, Eq)
|
|
|
|
-- | Type-safe wrapper for diagram identifiers
|
|
newtype DiagramId = DiagramId Text
|
|
deriving (Show, Eq)
|
|
|
|
-- | Configuration for diagram generation
|
|
data DiagramConfig = DiagramConfig
|
|
{ dcSourceDir :: SourceDir
|
|
, dcOutputDir :: OutputDir
|
|
, dcOutputFormat :: OutputFormat
|
|
} deriving (Show)
|
|
|
|
-- | Compute output directory from input file path
|
|
-- "docs/readme.md" -> "docs/output/readme"
|
|
computeOutputDir :: FilePath -> OutputDir
|
|
computeOutputDir inputPath =
|
|
let dir = takeDirectory inputPath
|
|
baseName = takeBaseName inputPath
|
|
in OutputDir $ if null dir || dir == "."
|
|
then "output" </> baseName
|
|
else dir </> "output" </> baseName
|
|
|
|
-- | Ensure output directory exists
|
|
ensureOutputDir :: OutputDir -> IO ()
|
|
ensureOutputDir (OutputDir dir) = createDirectoryIfMissing True dir
|
|
|
|
-- | State for heading-aware diagram naming during AST traversal
|
|
data TraversalState = TraversalState
|
|
{ tsCurrentHeading :: Maybe Text -- ^ Current heading text (normalized)
|
|
, tsHeadingCounters :: Map Text Int -- ^ Counter for diagrams per heading
|
|
, tsDocumentName :: Text -- ^ Fallback name when no heading
|
|
} deriving (Show, Eq)
|
|
|
|
-- | Create initial traversal state with document name as fallback
|
|
initialTraversalState :: Text -> TraversalState
|
|
initialTraversalState docName = TraversalState
|
|
{ tsCurrentHeading = Nothing
|
|
, tsHeadingCounters = Map.empty
|
|
, tsDocumentName = docName
|
|
}
|
|
|
|
-- | Normalize heading text for use as a filename
|
|
-- "File Flow Diagram!" -> "file_flow_diagram"
|
|
normalizeHeading :: Text -> Text
|
|
normalizeHeading = T.intercalate "_"
|
|
. T.words
|
|
. T.filter (\c -> isAlphaNum c || isSpace c)
|
|
. T.toLower |