module DataTypeTool.Common.Utils where import qualified Antelude.Function as Function import qualified Antelude.List as List import qualified Antelude.Maybe as Maybe import qualified Antelude.String.Case as Case import qualified Antelude.Tuple.Pair as Pair import Control.Monad ( mapM ) import qualified Data.Char as Char import qualified Data.Map.Strict as Map import qualified Data.Text as Text import Data.Traversable ( mapAccumM ) import qualified System.Directory as Dir import System.FilePath ( pathSeparator ) import System.IO ( readFile' ) import qualified Text.Casing as Casing data CaseType = PascalCase | CamelCase | ScreamingCase | CapitalizedSnakeCase | QuietSnakeCase | ScreamingSnakeCase typeFilePathToLangFilePath :: CaseType -> FilePath -> FilePath -> FilePath typeFilePathToLangFilePath caseType newExtension typeRelPath = let caseFn :: (String -> String) caseFn = case caseType of PascalCase -> Casing.pascal CamelCase -> Casing.camel ScreamingCase -> List.map Char.toUpper CapitalizedSnakeCase -> Function.identity QuietSnakeCase -> Casing.quietSnake ScreamingSnakeCase -> Casing.screamingSnake in typeRelPath |> List.reverse -- Drop .type suffix |> List.stripPrefix (List.reverse ".type") |> Maybe.withDefault (List.reverse typeRelPath) |> List.reverse |> List.drop 1 -- Remove prefixed '/' or '\\' |> split pathSeparator -- Split at '/' or '\\' |> List.map caseFn -- Case-ify |> List.intersperse [pathSeparator] -- Reinsert '/' or '\\' |> ([pathSeparator] :) -- Readd prefixed '/' or '\\' |> List.concat -- Merge |> (<> newExtension) -- New Extension -- The same as above, but without the actual file. -- Used with System.Directory.createDirectoryIfMissing to ensure we can write. typeFilePathToLangDirPath :: CaseType -> FilePath -> FilePath typeFilePathToLangDirPath caseType typeRelPath = let caseFn :: (String -> String) caseFn = case caseType of PascalCase -> Casing.pascal CamelCase -> Casing.camel ScreamingCase -> List.map Char.toUpper CapitalizedSnakeCase -> Function.identity QuietSnakeCase -> Casing.quietSnake ScreamingSnakeCase -> Casing.screamingSnake in typeRelPath |> List.reverse -- Drop .type suffix |> List.dropWhile (/= pathSeparator) |> List.reverse |> List.drop 1 -- Remove prefixed '/' or '\\' |> split pathSeparator -- Split at '/' or '\\' |> List.map caseFn -- Case-ify |> List.intersperse [pathSeparator] -- Reinsert '/' or '\\' |> ([pathSeparator] :) -- Readd prefixed '/' or '\\' |> List.concat -- Merge typeFilePathToLangCodePath :: CaseType -> Char -> FilePath -> String typeFilePathToLangCodePath caseType separator typeRelPath = let caseFn :: (String -> String) caseFn = case caseType of PascalCase -> Casing.pascal CamelCase -> Casing.camel ScreamingCase -> List.map Char.toUpper CapitalizedSnakeCase -> Function.identity QuietSnakeCase -> Casing.quietSnake ScreamingSnakeCase -> Casing.screamingSnake in typeRelPath |> List.reverse -- Drop .type suffix |> List.stripPrefix (List.reverse ".type") |> Maybe.withDefault (List.reverse typeRelPath) |> List.reverse |> List.dropWhile (== pathSeparator) -- Remove prefixed '/' or '\\' |> split pathSeparator -- Split at '/' or '\\' |> List.map caseFn -- Case-ify |> List.intersperse [separator] -- Insert langage's file separator |> List.concat -- Merge split :: Char -> String -> [String] split chr str = case List.break (== chr) str of (a, chr : b) -> a : split chr b (a, "") -> [a] recurseDirectory :: FilePath -> IO [(FilePath, String)] recurseDirectory dp = let traverseDirs :: [(FilePath, String)] -> FilePath -> IO ([(FilePath, String)], [(FilePath, String)]) traverseDirs state pth = let fullPth :: FilePath fullPth = dp <> [pathSeparator] <> pth in Dir.doesDirectoryExist fullPth >>= \case True -> recurseDirectory fullPth >>= \dirsResult -> return (state <> dirsResult, dirsResult) False -> Dir.doesFileExist fullPth >>= \case True -> if List.isSuffixOf ".type" fullPth then readFile' fullPth >>= \result -> return ( state <> [(fullPth, result)] , [(fullPth, result)] ) else return (state, []) False -> return (state, []) in Dir.listDirectory dp >>= mapAccumM traverseDirs [] >>= return <. Pair.first createWritePath :: FilePath -> IO () createWritePath = Dir.createDirectoryIfMissing True between :: (Ord a) => a -> a -> a -> Bool between input lower upper = lower < input && input < upper betweenOrEqualLower :: (Ord a) => a -> a -> a -> Bool betweenOrEqualLower input lower upper = lower <= input && input < upper betweenOrEqualUpper :: (Ord a) => a -> a -> a -> Bool betweenOrEqualUpper input lower upper = lower < input && input <= upper