{-| Shikensu. See the README and tests for examples. -} module Shikensu ( forkDefinition , list , listF , listRelative , listRelativeF , makeDefinition , makeDictionary , module Shikensu.Internal.Types ) where import Data.Monoid ((<>)) import Flow import Shikensu.Internal.Types import Shikensu.Internal.Utilities import System.FilePath import qualified Data.HashMap.Strict as HashMap (empty) import qualified Data.List as List (concatMap, map, zip) import qualified System.Directory as Dir (canonicalizePath) import qualified System.FilePath.Glob as Glob (compile, globDir1) -- IO {-| Make a single dictionary based on a path to a directory and multiple glob patterns. 1. Compile patterns so `globDir` can use them. 2. Run `globDir` function on the given (root) path. 3. We get a list back for each pattern (ie. a list of lists), here we put each child list in a tuple along with its pattern. 4. We make a Dictionary out of each tuple (this also needs the path). 5. Merge the dictionaries into one dictionary. > list ["*.md"] "/root/articles" -} list :: [String] -> FilePath -> IO Dictionary list patterns rootDir = patterns |> List.map (Glob.compile) |> List.map (flip Glob.globDir1 $ rootDir) |> sequence |> fmap (List.zip patterns) |> fmap (List.concatMap $ makeDictionary rootDir) {-| Flipped version of `list`. -} listF :: FilePath -> [String] -> IO Dictionary listF = flip list {-| Same as `list`, but given a relative directory. > listRelative ["*.md"] "./articles" -} listRelative :: [String] -> FilePath -> IO Dictionary listRelative patterns relativePath = Dir.canonicalizePath relativePath >>= list patterns {-| Flipped version `listRelative`. -} listRelativeF :: FilePath -> [String] -> IO Dictionary listRelativeF = flip listRelative -- PURE {-| Fork a Definition. -} forkDefinition :: FilePath -> Definition -> Definition forkDefinition newLocalPath def = Definition { basename = takeBaseName newLocalPath , dirname = takeDirName newLocalPath , extname = takeExtension newLocalPath , pattern = (pattern def) , rootDirname = (rootDirname def) , workingDirname = (workingDirname def) -- Additional properties , content = (content def) , metadata = (metadata def) , parentPath = compileParentPath $ takeDirName newLocalPath , pathToRoot = compilePathToRoot $ takeDirName newLocalPath } {-| Make a Definition. Example definition, given: - the root path `/Users/icidasset/Projects/shikensu` - the pattern `example/**/*.md` - the absolute path `/Users/icidasset/Projects/shikensu/example/test/hello.md` > Definition > { basename = "hello" > , dirname = "test" > , extname = ".md" > , pattern = "example/**/*.md" > , rootDirname = "/Users/icidasset/Projects/shikensu" > , workingDirname = "example" > > , content = Nothing > , metadata = HashMap.empty > , parentPath = "../" > , pathToRoot = "../../" > } -} makeDefinition :: FilePath -> String -> FilePath -> Definition makeDefinition rootDirname pattern absolutePath = let workingDirname = commonDirectory pattern rootWorkingDirname = combine rootDirname workingDirname theAbsolutePath = normalise absolutePath theLocalPath = dropDrive (stripPrefix rootWorkingDirname theAbsolutePath) in Definition { basename = takeBaseName theLocalPath , dirname = takeDirName theLocalPath , extname = takeExtension theLocalPath , pattern = pattern , rootDirname = rootDirname , workingDirname = workingDirname -- Additional properties , content = Nothing , metadata = HashMap.empty , parentPath = compileParentPath $ takeDirName theLocalPath , pathToRoot = compilePathToRoot $ takeDirName theLocalPath } {-| Make a Dictionary. -} makeDictionary :: FilePath -> (String, [FilePath]) -> Dictionary makeDictionary rootDirname (pattern, filepaths) = List.map (makeDefinition rootDirname pattern) filepaths