From af89d2a5ab6fbd3c4de80351ddebb346991976de Mon Sep 17 00:00:00 2001 From: Steven Vandevelde Date: Tue, 3 Oct 2023 16:29:16 +0200 Subject: [PATCH] 4.0.0 --- CHANGELOG.md | 4 ++++ docs.json | 2 +- gren.json | 2 +- src/Shikensu.gren | 36 ++++++++++++++++++++++++++++-------- src/Shikensu/Path.gren | 22 ++-------------------- 5 files changed, 36 insertions(+), 30 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 552e3ad..731a76d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## 4.0.0 + +Moved the `currentWorkingDirectory` to the main `Shikensu` module so that it can use the `Error` type instead for ease of use. + ## 3.0.0 * Added `Shikensu.perform` diff --git a/docs.json b/docs.json index 8e351a2..11988dc 100644 --- a/docs.json +++ b/docs.json @@ -1 +1 @@ -{"Shikensu":{"name":"Shikensu","comment":"\n\n# ๐Ÿš€\n\n@docs program, programs, Program, list, perform, Task\n\n\n# IO\n\n@docs read, write, writeDefinition\n\n","unions":[],"aliases":[{"name":"Program","comment":" Alias for a Node program.\n","args":[],"type":"Node.Program {} {}"},{"name":"Task","comment":" Alias for the main `Task` type we'll be working with here.\n","args":[],"type":"Task.Task Shikensu.Error.Error Shikensu.Bundle.Bundle"}],"values":[{"name":"list","comment":" The `list` function itself, unwrapped.\n\nRecursively lists a directory and then gives you a `Task`\ncontaining a `Bundle` which in turns has an array of `Definition`s\nstored under the property named `compendium`.\n\nThis collection of `Definition`s is the main thing you'll be working with.\nThe goal of this library is to scan a file tree, manipulate it and then\noptionally write it back to disk. This is done through these definitions.\n\n import Shikensu\n import Shikensu.Focus exposing (Focus(..))\n\n Shikensu.perform\n -- To ignore, return `Cmd.none`\n { onSuccess = \\env _ -> Stream.sendLine env.stdout \"๐Ÿงช Sequence completed\"\n , onError = \\env err -> Stream.sendLine env.stderr (\"๐Ÿšจ \" ++ Error.toString err)\n }\n (\\fsPermission ->\n CurrentDirectory\n |> Shikensu.list fsPermission\n |> Task.map (Shikensu.withExtension \"md\")\n )\n\nโš ๏ธ The given `Focus` will always be in the context of\nthe environment of the resulting Gren binary that is being executed.\nSo for example, say your `pwd` command returns `~/code/shikensu/`,\nand your focus is `Relative (Path.Directory [ \"..\", \"example\" ])`.\nIf you run `./binary/app` the resulting path will be `~/code/example/`.\n\n","type":"FileSystem.Permission -> Shikensu.Focus.Focus -> Shikensu.Task"},{"name":"perform","comment":" A utility function that helps you create programs.\n\nThis uses `Node.defineSimpleProgram` and `FileSystem.initialize` underneath\nand then manages the `Shikensu.Task` value created by `list` or some other function.\n\nSee the `list` function above for an example.\n\n","type":"{ onSuccess : Node.Environment -> a -> Platform.Cmd.Cmd {}, onError : Node.Environment -> Shikensu.Error.Error -> Platform.Cmd.Cmd {} } -> (FileSystem.Permission -> Task.Task Shikensu.Error.Error a) -> Shikensu.Program"},{"name":"program","comment":" Create a Shikensu Program.\n\nThis is basically a wrapper around `list` and `perform`\nthat creates a SimpleProgram for you and initialises the needed permissions.\n\nIt also prints errors to stderr or a success message to stdout.\n\n import Shikensu\n import Shikensu.Contrib as Shikensu\n import Shikensu.Focus exposing (Focus(..))\n import Task\n\n Shikensu.program sequence CurrentDirectory\n\n sequence task =\n task\n |> Task.map (Shikensu.withExtension \"md\")\n |> Task.andThen Shikensu.read\n |> Task.map (Shikensu.renderContent markdownRenderer) -- See `example` folder\n |> Task.andThen (Shikensu.write destinationFocus)\n\n\n","type":"(Shikensu.Task -> Shikensu.Task) -> Shikensu.Focus.Focus -> Shikensu.Program"},{"name":"programs","comment":" Provides a way to make and operate on multiple lists.\n\nTechnically not multiple programs, but same idea as\nthe `program` function, just with multiple lists.\n\n import Shikensu\n import Shikensu.Focus exposing (Focus(..))\n\n Shikensu.programs\n [ { focus = Relative (Path.directory [ \"posts\" ])\n , sequence = Task.andThen Shikensu.read\n }\n , { focus = Relative (Path.directory [ \"images\" ])\n , sequence = Task.map (\\bundle -> ...)\n }\n ]\n\n","type":"Array.Array { focus : Shikensu.Focus.Focus, sequence : Shikensu.Task -> Shikensu.Task } -> Shikensu.Program"},{"name":"read","comment":" Read the files in the given compendium/bundle,\nsetting the `content` property in the definition.\n","type":"Shikensu.Bundle.Bundle -> Shikensu.Task"},{"name":"write","comment":" Write each definition to their respective location.\nThe location will depend on the focus and the environment it was run in.\n","type":"Shikensu.Focus.Focus -> Shikensu.Bundle.Bundle -> Shikensu.Task"},{"name":"writeDefinition","comment":" โš ๏ธ You most likely want to use `write` instead. This function is used internally by `write` but is exposed for special use cases.\n\nWrite a definition to its respective location.\nThe location will depend on the given directory path and the environment it was run in.\nThe given directory path must be an absolute path!\n\n","type":"FileSystem.Permission -> Shikensu.Path.Path Shikensu.Path.Directory -> Shikensu.Definition.Definition -> Task.Task Shikensu.Error.Error {}"}],"binops":[]},"Shikensu.Bundle":{"name":"Shikensu.Bundle","comment":"\n\n# Bundle\n\n@docs Bundle, mapCompendium\n\n","unions":[],"aliases":[{"name":"Bundle","comment":" The bundle which is the value of the `Shikensu.Task` type.\n\nMost important part here is the `compendium`, the list of definitions.\nThe rest is contextual information.\n\n","args":[],"type":"{ compendium : Array.Array Shikensu.Definition.Definition, fsPermission : FileSystem.Permission, focusDirectory : Shikensu.Path.Path Shikensu.Path.Directory, workingDirectory : Shikensu.Path.Path Shikensu.Path.Directory }"}],"values":[{"name":"mapCompendium","comment":" Convenience function to map over array of `Definition`s.\n","type":"(Array.Array Shikensu.Definition.Definition -> Array.Array Shikensu.Definition.Definition) -> Shikensu.Bundle.Bundle -> Shikensu.Bundle.Bundle"}],"binops":[]},"Shikensu.Contrib":{"name":"Shikensu.Contrib","comment":"\n\nPremade functions to manipulate your bundles/definitions with.\n\n\n# Contrib\n\n@docs clearMetadata, clone, copyPropsToMetadata, exclude, insertMetadata, permalink, rename, renameExtension, renderContent, replaceMetadata, setContent, transformContent, withBaseName, withDirectory, withExtension, withMetadata\n\n","unions":[],"aliases":[],"values":[{"name":"clearMetadata","comment":" Clear metadata.\n","type":"Shikensu.Bundle.Bundle -> Shikensu.Bundle.Bundle"},{"name":"clone","comment":" Clone.\n\nFor each definition that has the given `relativePath` (1st argument),\nmake a clone with a new `relativePath` (2nd argument),\nand add that into the compendium just after the matching definition.\n\n >>> clone \"index.html\" \"200.html\" bundle\n\n","type":"Shikensu.Path.Path Shikensu.Path.File -> Shikensu.Path.Path Shikensu.Path.File -> Shikensu.Bundle.Bundle -> Shikensu.Bundle.Bundle"},{"name":"copyPropsToMetadata","comment":" Copy definition properties into the metadata.\n","type":"Shikensu.Bundle.Bundle -> Shikensu.Bundle.Bundle"},{"name":"exclude","comment":" Exclude.\n\nFilter out the definitions that have the given `relativePath`.\n\n","type":"Shikensu.Path.Path Shikensu.Path.File -> Shikensu.Bundle.Bundle -> Shikensu.Bundle.Bundle"},{"name":"insertMetadata","comment":" Insert additional metadata.\n","type":"Dict.Dict String.String Json.Encode.Value -> Shikensu.Bundle.Bundle -> Shikensu.Bundle.Bundle"},{"name":"permalink","comment":" Permalink.\n\nAppend the baseName to the directoryPath\nand change the baseName to the given string.\nIt will NOT change definitions that already have the new baseName.\n\n >>> permalink \"index\" compendium\n\n","type":"String.String -> Shikensu.Bundle.Bundle -> Shikensu.Bundle.Bundle"},{"name":"rename","comment":" Rename.\n\nChange the `relativePath` of the definitions that match a given `relativePath`.\nFor example, if you have a definition with the relativePath path `a/b/example.html`:\n\n >>> rename\n ..> (Path.file [ \"a\", \"b\", \"example.html\" ])\n ..> (Path.file [ \"example\", \"index.html\" ])\n ..> compendium\n\n","type":"Shikensu.Path.Path Shikensu.Path.File -> Shikensu.Path.Path Shikensu.Path.File -> Shikensu.Bundle.Bundle -> Shikensu.Bundle.Bundle"},{"name":"renameExtension","comment":" Rename extension.\n\nExample:\n\n >>> renameExtension \"markdown\" \"html\" compendium\n ..> -- The definitions that had the extensionName \"markdown\"\n ..> -- now have the extensionName \"html\"\n\n","type":"String.String -> String.String -> Shikensu.Bundle.Bundle -> Shikensu.Bundle.Bundle"},{"name":"renderContent","comment":" Render content.\n\nReplace the `content` property by providing a renderer.\nA renderer is a function with the signature `Definition -> Maybe Bytes`.\nYou can use this to render templates, markdown, etc.\n\n","type":"(Shikensu.Definition.Definition -> Maybe.Maybe Bytes.Bytes) -> Shikensu.Bundle.Bundle -> Shikensu.Bundle.Bundle"},{"name":"replaceMetadata","comment":" Replace metadata.\n\nReplace the current metadata dictionary with another one.\n\n","type":"Dict.Dict String.String Json.Encode.Value -> Shikensu.Bundle.Bundle -> Shikensu.Bundle.Bundle"},{"name":"setContent","comment":" Set content.\n\nSet content directly.\n\n","type":"Bytes.Bytes -> Shikensu.Bundle.Bundle -> Shikensu.Bundle.Bundle"},{"name":"transformContent","comment":" Transform content.\n\nAlias for `renderContent`.\n\n","type":"(Shikensu.Definition.Definition -> Maybe.Maybe Bytes.Bytes) -> Shikensu.Bundle.Bundle -> Shikensu.Bundle.Bundle"},{"name":"withBaseName","comment":" Only keep definitions with the given base name.\n","type":"String.String -> Shikensu.Bundle.Bundle -> Shikensu.Bundle.Bundle"},{"name":"withDirectory","comment":" Only keep definitions with the given directory path.\n","type":"Shikensu.Path.Path Shikensu.Path.Directory -> Shikensu.Bundle.Bundle -> Shikensu.Bundle.Bundle"},{"name":"withExtension","comment":" Only keep definitions with the given extension.\n","type":"String.String -> Shikensu.Bundle.Bundle -> Shikensu.Bundle.Bundle"},{"name":"withMetadata","comment":" Only keep definitions with the given metadata.\n","type":"String.String -> Json.Encode.Value -> Shikensu.Bundle.Bundle -> Shikensu.Bundle.Bundle"}],"binops":[]},"Shikensu.Definition":{"name":"Shikensu.Definition","comment":"\n\n# Definition\n\n@docs Definition, create, fork, relativePath\n\n","unions":[],"aliases":[{"name":"Definition","comment":" **A piece of content.**\n\nExample definition, given:\nThe working directory root path `/Users/icidasset/Projects/shikensu/example/`\nand the full item path `/Users/icidasset/Projects/shikensu/example/test/hello.md`\n\n { baseName = \"hello\"\n , content = Nothing\n , directoryPath = Path.directory [ \"test\" ]\n , extensionName = Just \"md\"\n , metadata = Dict.empty\n }\n\n","args":[],"type":"{ baseName : String.String, content : Maybe.Maybe Bytes.Bytes, directoryPath : Shikensu.Path.Path Shikensu.Path.Directory, extensionName : Maybe.Maybe String.String, metadata : Dict.Dict String.String Json.Encode.Value }"}],"values":[{"name":"create","comment":" Create a definition, given a relative path.\n","type":"Shikensu.Path.Path Shikensu.Path.File -> Shikensu.Definition.Definition"},{"name":"fork","comment":" Fork a definition, given a relative path.\nTaking the metadata and content of the original definition.\n","type":"Shikensu.Path.Path Shikensu.Path.File -> Shikensu.Definition.Definition -> Shikensu.Definition.Definition"},{"name":"relativePath","comment":" The path relative to the working directory.\n","type":"Shikensu.Definition.Definition -> Shikensu.Path.Path Shikensu.Path.File"}],"binops":[]},"Shikensu.Error":{"name":"Shikensu.Error","comment":"\n\n# Error\n\n@docs Error, toString\n\n","unions":[{"name":"Error","comment":"","args":[],"cases":[["ErrorMessage",["String.String"]],["PlatformAccessError",["Shikensu.Path.Path Shikensu.Path.Encapsulated","FileSystem.AccessError"]],["PlatformUnknownError",["FileSystem.UnknownFileSystemError"]]]}],"aliases":[],"values":[{"name":"toString","comment":"","type":"Shikensu.Error.Error -> String.String"}],"binops":[]},"Shikensu.Focus":{"name":"Shikensu.Focus","comment":"\n\n# Focus\n\n@docs Focus, toAbsolutePath\n\n","unions":[{"name":"Focus","comment":"","args":[],"cases":[["CurrentDirectory",[]],["Relative",["Shikensu.Path.Path Shikensu.Path.Directory"]],["Absolute",["Shikensu.Path.Path Shikensu.Path.Directory"]]]}],"aliases":[],"values":[{"name":"toAbsolutePath","comment":"","type":"{ cwd : Shikensu.Path.Path Shikensu.Path.Directory } -> Shikensu.Focus.Focus -> Shikensu.Path.Path Shikensu.Path.Directory"}],"binops":[]},"Shikensu.Path":{"name":"Shikensu.Path","comment":"\n\n# Paths\n\n@docs Path, Directory, File, Encapsulated, Kind\n\n\n# Creation\n\n@docs directory, file, currentWorkingDirectory\n\n\n# POSIX\n\n@docs fromPosix, toPosix\n\n\n# Encapsulation\n\n@docs encapsulate\n\n\n# Functions\n\n@docs combine, kind, length, map, unwrap\n\n","unions":[{"name":"Directory","comment":" ๐Ÿ‘ป Directory\n","args":[],"cases":[]},{"name":"Encapsulated","comment":" ๐Ÿ‘ป Encapsulated\n","args":[],"cases":[]},{"name":"File","comment":" ๐Ÿ‘ป File\n","args":[],"cases":[]},{"name":"Kind","comment":" ","args":[],"cases":[["Directory",[]],["File",[]]]},{"name":"Path","comment":" Path type.\nThis is used with the [phantom ๐Ÿ‘ป types](#phantom-types).\n\n directoryPath : Path Directory\n filePath : Path File\n encapsulatedPath : Path Encapsulated\n\n","args":["kind"],"cases":[]}],"aliases":[],"values":[{"name":"combine","comment":" Combine a directory path and another path.\n\n","type":"Shikensu.Path.Path Shikensu.Path.Directory -> Shikensu.Path.Path kind -> Shikensu.Path.Path kind"},{"name":"currentWorkingDirectory","comment":" Get the absolute directory path of the current working directory.\n","type":"FileSystem.Permission -> Task.Task Basics.Never (Shikensu.Path.Path Shikensu.Path.Directory)"},{"name":"directory","comment":" Create a directory path.\n\n directory [ \"Audio\", \"Playlists\" ]\n\n","type":"Array.Array String.String -> Shikensu.Path.Path Shikensu.Path.Directory"},{"name":"encapsulate","comment":" Encapsulate a path.\n","type":"Shikensu.Path.Path kind -> Shikensu.Path.Path Shikensu.Path.Encapsulated"},{"name":"file","comment":" Create a file path.\n\n file [ \"Document\", \"invoice.pdf\" ]\n\n","type":"Array.Array String.String -> Shikensu.Path.Path Shikensu.Path.File"},{"name":"fromPosix","comment":" Convert a POSIX formatted string to a path.\nThis will return a `Encapsulated` path. To get a path of the type `Path Directory` or `Path File`, use the functions in the `Webnative.Path.Encapsulated` module.\n\n >>> import Shikensu.Path.Encapsulated\n >>> \"foo/bar/\"\n ..> |> fromPosix\n ..> |> Shikensu.Path.Encapsulated.toDirectory\n Just (directory [ \"foo\", \"bar\" ])\n\n >>> \"foo/bar\"\n ..> |> fromPosix\n ..> |> Shikensu.Path.Encapsulated.toFile\n Just (file [ \"foo\", \"bar\" ])\n\n","type":"String.String -> Shikensu.Path.Path Shikensu.Path.Encapsulated"},{"name":"kind","comment":" Get the path kind.\n\n >>> kind (directory [])\n Directory\n >>> kind (file [])\n File\n\nEven if a path is encapsulated,\nyou can still check the kind of path it is.\n\n >>> kind (encapsulate <| directory [])\n Directory\n >>> kind (encapsulate <| file [])\n File\n\n","type":"Shikensu.Path.Path kind -> Shikensu.Path.Kind"},{"name":"length","comment":" Length.\n","type":"Shikensu.Path.Path kind -> Basics.Int"},{"name":"map","comment":" Map.\n","type":"(Array.Array String.String -> Array.Array String.String) -> Shikensu.Path.Path kind -> Shikensu.Path.Path kind"},{"name":"toPosix","comment":" Convert a path to the POSIX format.\n\n >>> toPosix { absolute = True } (directory [ \"foo\", \"bar\"])\n \"/foo/bar/\"\n >>> toPosix { absolute = False } (file [ \"foo\", \"bar\"])\n \"foo/bar\"\n\n","type":"{ absolute : Basics.Bool } -> Shikensu.Path.Path kind -> String.String"},{"name":"unwrap","comment":" Get the path parts.\n\n >>> unwrap (directory [ \"foo\", \"bar\" ])\n [ \"foo\", \"bar\" ]\n >>> unwrap (file [ \"foo\", \"bar\" ])\n [ \"foo\", \"bar\" ]\n\n","type":"Shikensu.Path.Path kind -> Array.Array String.String"}],"binops":[]},"Shikensu.Path.Encapsulated":{"name":"Shikensu.Path.Encapsulated","comment":"\n\n# Encapsulated Paths\n\n@docs toDirectory, toFile\n\n","unions":[],"aliases":[],"values":[{"name":"toDirectory","comment":" Remove the membrane and extract a `Path Directory`.\n","type":"Shikensu.Path.Path Shikensu.Path.Encapsulated -> Maybe.Maybe (Shikensu.Path.Path Shikensu.Path.Directory)"},{"name":"toFile","comment":" Remove the membrane and extract a `Path File`.\n","type":"Shikensu.Path.Path Shikensu.Path.Encapsulated -> Maybe.Maybe (Shikensu.Path.Path Shikensu.Path.File)"}],"binops":[]}} \ No newline at end of file +{"Shikensu":{"name":"Shikensu","comment":"\n\n# ๐Ÿš€\n\n@docs program, programs, Program, Task, list, perform\n\n\n# IO\n\n@docs read, write, writeDefinition\n\n\n# ๐Ÿ› ๏ธ\n\n@docs currentWorkingDirectory\n\n","unions":[],"aliases":[{"name":"Program","comment":" Alias for a Node program.\n","args":[],"type":"Node.Program {} {}"},{"name":"Task","comment":" Alias for the main `Task` type we'll be working with here.\n","args":[],"type":"Task.Task Shikensu.Error.Error Shikensu.Bundle.Bundle"}],"values":[{"name":"currentWorkingDirectory","comment":" Get the absolute directory path of the current working directory.\n","type":"FileSystem.Permission -> Task.Task Shikensu.Error.Error (Shikensu.Path.Path Shikensu.Path.Directory)"},{"name":"list","comment":" The `list` function itself, unwrapped.\n\nRecursively lists a directory and then gives you a `Task`\ncontaining a `Bundle` which in turns has an array of `Definition`s\nstored under the property named `compendium`.\n\nThis collection of `Definition`s is the main thing you'll be working with.\nThe goal of this library is to scan a file tree, manipulate it and then\noptionally write it back to disk. This is done through these definitions.\n\n import Shikensu\n import Shikensu.Focus exposing (Focus(..))\n\n Shikensu.perform\n -- To ignore, return `Cmd.none`\n { onSuccess = \\env _ -> Stream.sendLine env.stdout \"๐Ÿงช Sequence completed\"\n , onError = \\env err -> Stream.sendLine env.stderr (\"๐Ÿšจ \" ++ Error.toString err)\n }\n (\\fsPermission ->\n CurrentDirectory\n |> Shikensu.list fsPermission\n |> Task.map (Shikensu.withExtension \"md\")\n )\n\nโš ๏ธ The given `Focus` will always be in the context of\nthe environment of the resulting Gren binary that is being executed.\nSo for example, say your `pwd` command returns `~/code/shikensu/`,\nand your focus is `Relative (Path.Directory [ \"..\", \"example\" ])`.\nIf you run `./binary/app` the resulting path will be `~/code/example/`.\n\n","type":"FileSystem.Permission -> Shikensu.Focus.Focus -> Shikensu.Task"},{"name":"perform","comment":" A utility function that helps you create programs.\n\nThis uses `Node.defineSimpleProgram` and `FileSystem.initialize` underneath\nand then manages the `Shikensu.Task` value created by `list` or some other function.\n\nSee the `list` function above for an example.\n\n","type":"{ onSuccess : Node.Environment -> a -> Platform.Cmd.Cmd {}, onError : Node.Environment -> Shikensu.Error.Error -> Platform.Cmd.Cmd {} } -> (FileSystem.Permission -> Task.Task Shikensu.Error.Error a) -> Shikensu.Program"},{"name":"program","comment":" Create a Shikensu Program.\n\nThis is basically a wrapper around `list` and `perform`\nthat creates a SimpleProgram for you and initialises the needed permissions.\n\nIt also prints errors to stderr or a success message to stdout.\n\n import Shikensu\n import Shikensu.Contrib as Shikensu\n import Shikensu.Focus exposing (Focus(..))\n import Task\n\n Shikensu.program sequence CurrentDirectory\n\n sequence task =\n task\n |> Task.map (Shikensu.withExtension \"md\")\n |> Task.andThen Shikensu.read\n |> Task.map (Shikensu.renderContent markdownRenderer) -- See `example` folder\n |> Task.andThen (Shikensu.write destinationFocus)\n\n\n","type":"(Shikensu.Task -> Shikensu.Task) -> Shikensu.Focus.Focus -> Shikensu.Program"},{"name":"programs","comment":" Provides a way to make and operate on multiple lists.\n\nTechnically not multiple programs, but same idea as\nthe `program` function, just with multiple lists.\n\n import Shikensu\n import Shikensu.Focus exposing (Focus(..))\n\n Shikensu.programs\n [ { focus = Relative (Path.directory [ \"posts\" ])\n , sequence = Task.andThen Shikensu.read\n }\n , { focus = Relative (Path.directory [ \"images\" ])\n , sequence = Task.map (\\bundle -> ...)\n }\n ]\n\n","type":"Array.Array { focus : Shikensu.Focus.Focus, sequence : Shikensu.Task -> Shikensu.Task } -> Shikensu.Program"},{"name":"read","comment":" Read the files in the given compendium/bundle,\nsetting the `content` property in the definition.\n","type":"Shikensu.Bundle.Bundle -> Shikensu.Task"},{"name":"write","comment":" Write each definition to their respective location.\nThe location will depend on the focus and the environment it was run in.\n","type":"Shikensu.Focus.Focus -> Shikensu.Bundle.Bundle -> Shikensu.Task"},{"name":"writeDefinition","comment":" โš ๏ธ You most likely want to use `write` instead. This function is used internally by `write` but is exposed for special use cases.\n\nWrite a definition to its respective location.\nThe location will depend on the given directory path and the environment it was run in.\nThe given directory path must be an absolute path!\n\n","type":"FileSystem.Permission -> Shikensu.Path.Path Shikensu.Path.Directory -> Shikensu.Definition.Definition -> Task.Task Shikensu.Error.Error {}"}],"binops":[]},"Shikensu.Bundle":{"name":"Shikensu.Bundle","comment":"\n\n# Bundle\n\n@docs Bundle, mapCompendium\n\n","unions":[],"aliases":[{"name":"Bundle","comment":" The bundle which is the value of the `Shikensu.Task` type.\n\nMost important part here is the `compendium`, the list of definitions.\nThe rest is contextual information.\n\n","args":[],"type":"{ compendium : Array.Array Shikensu.Definition.Definition, fsPermission : FileSystem.Permission, focusDirectory : Shikensu.Path.Path Shikensu.Path.Directory, workingDirectory : Shikensu.Path.Path Shikensu.Path.Directory }"}],"values":[{"name":"mapCompendium","comment":" Convenience function to map over array of `Definition`s.\n","type":"(Array.Array Shikensu.Definition.Definition -> Array.Array Shikensu.Definition.Definition) -> Shikensu.Bundle.Bundle -> Shikensu.Bundle.Bundle"}],"binops":[]},"Shikensu.Contrib":{"name":"Shikensu.Contrib","comment":"\n\nPremade functions to manipulate your bundles/definitions with.\n\n\n# Contrib\n\n@docs clearMetadata, clone, copyPropsToMetadata, exclude, insertMetadata, permalink, rename, renameExtension, renderContent, replaceMetadata, setContent, transformContent, withBaseName, withDirectory, withExtension, withMetadata\n\n","unions":[],"aliases":[],"values":[{"name":"clearMetadata","comment":" Clear metadata.\n","type":"Shikensu.Bundle.Bundle -> Shikensu.Bundle.Bundle"},{"name":"clone","comment":" Clone.\n\nFor each definition that has the given `relativePath` (1st argument),\nmake a clone with a new `relativePath` (2nd argument),\nand add that into the compendium just after the matching definition.\n\n >>> clone \"index.html\" \"200.html\" bundle\n\n","type":"Shikensu.Path.Path Shikensu.Path.File -> Shikensu.Path.Path Shikensu.Path.File -> Shikensu.Bundle.Bundle -> Shikensu.Bundle.Bundle"},{"name":"copyPropsToMetadata","comment":" Copy definition properties into the metadata.\n","type":"Shikensu.Bundle.Bundle -> Shikensu.Bundle.Bundle"},{"name":"exclude","comment":" Exclude.\n\nFilter out the definitions that have the given `relativePath`.\n\n","type":"Shikensu.Path.Path Shikensu.Path.File -> Shikensu.Bundle.Bundle -> Shikensu.Bundle.Bundle"},{"name":"insertMetadata","comment":" Insert additional metadata.\n","type":"Dict.Dict String.String Json.Encode.Value -> Shikensu.Bundle.Bundle -> Shikensu.Bundle.Bundle"},{"name":"permalink","comment":" Permalink.\n\nAppend the baseName to the directoryPath\nand change the baseName to the given string.\nIt will NOT change definitions that already have the new baseName.\n\n >>> permalink \"index\" compendium\n\n","type":"String.String -> Shikensu.Bundle.Bundle -> Shikensu.Bundle.Bundle"},{"name":"rename","comment":" Rename.\n\nChange the `relativePath` of the definitions that match a given `relativePath`.\nFor example, if you have a definition with the relativePath path `a/b/example.html`:\n\n >>> rename\n ..> (Path.file [ \"a\", \"b\", \"example.html\" ])\n ..> (Path.file [ \"example\", \"index.html\" ])\n ..> compendium\n\n","type":"Shikensu.Path.Path Shikensu.Path.File -> Shikensu.Path.Path Shikensu.Path.File -> Shikensu.Bundle.Bundle -> Shikensu.Bundle.Bundle"},{"name":"renameExtension","comment":" Rename extension.\n\nExample:\n\n >>> renameExtension \"markdown\" \"html\" compendium\n ..> -- The definitions that had the extensionName \"markdown\"\n ..> -- now have the extensionName \"html\"\n\n","type":"String.String -> String.String -> Shikensu.Bundle.Bundle -> Shikensu.Bundle.Bundle"},{"name":"renderContent","comment":" Render content.\n\nReplace the `content` property by providing a renderer.\nA renderer is a function with the signature `Definition -> Maybe Bytes`.\nYou can use this to render templates, markdown, etc.\n\n","type":"(Shikensu.Definition.Definition -> Maybe.Maybe Bytes.Bytes) -> Shikensu.Bundle.Bundle -> Shikensu.Bundle.Bundle"},{"name":"replaceMetadata","comment":" Replace metadata.\n\nReplace the current metadata dictionary with another one.\n\n","type":"Dict.Dict String.String Json.Encode.Value -> Shikensu.Bundle.Bundle -> Shikensu.Bundle.Bundle"},{"name":"setContent","comment":" Set content.\n\nSet content directly.\n\n","type":"Bytes.Bytes -> Shikensu.Bundle.Bundle -> Shikensu.Bundle.Bundle"},{"name":"transformContent","comment":" Transform content.\n\nAlias for `renderContent`.\n\n","type":"(Shikensu.Definition.Definition -> Maybe.Maybe Bytes.Bytes) -> Shikensu.Bundle.Bundle -> Shikensu.Bundle.Bundle"},{"name":"withBaseName","comment":" Only keep definitions with the given base name.\n","type":"String.String -> Shikensu.Bundle.Bundle -> Shikensu.Bundle.Bundle"},{"name":"withDirectory","comment":" Only keep definitions with the given directory path.\n","type":"Shikensu.Path.Path Shikensu.Path.Directory -> Shikensu.Bundle.Bundle -> Shikensu.Bundle.Bundle"},{"name":"withExtension","comment":" Only keep definitions with the given extension.\n","type":"String.String -> Shikensu.Bundle.Bundle -> Shikensu.Bundle.Bundle"},{"name":"withMetadata","comment":" Only keep definitions with the given metadata.\n","type":"String.String -> Json.Encode.Value -> Shikensu.Bundle.Bundle -> Shikensu.Bundle.Bundle"}],"binops":[]},"Shikensu.Definition":{"name":"Shikensu.Definition","comment":"\n\n# Definition\n\n@docs Definition, create, fork, relativePath\n\n","unions":[],"aliases":[{"name":"Definition","comment":" **A piece of content.**\n\nExample definition, given:\nThe working directory root path `/Users/icidasset/Projects/shikensu/example/`\nand the full item path `/Users/icidasset/Projects/shikensu/example/test/hello.md`\n\n { baseName = \"hello\"\n , content = Nothing\n , directoryPath = Path.directory [ \"test\" ]\n , extensionName = Just \"md\"\n , metadata = Dict.empty\n }\n\n","args":[],"type":"{ baseName : String.String, content : Maybe.Maybe Bytes.Bytes, directoryPath : Shikensu.Path.Path Shikensu.Path.Directory, extensionName : Maybe.Maybe String.String, metadata : Dict.Dict String.String Json.Encode.Value }"}],"values":[{"name":"create","comment":" Create a definition, given a relative path.\n","type":"Shikensu.Path.Path Shikensu.Path.File -> Shikensu.Definition.Definition"},{"name":"fork","comment":" Fork a definition, given a relative path.\nTaking the metadata and content of the original definition.\n","type":"Shikensu.Path.Path Shikensu.Path.File -> Shikensu.Definition.Definition -> Shikensu.Definition.Definition"},{"name":"relativePath","comment":" The path relative to the working directory.\n","type":"Shikensu.Definition.Definition -> Shikensu.Path.Path Shikensu.Path.File"}],"binops":[]},"Shikensu.Error":{"name":"Shikensu.Error","comment":"\n\n# Error\n\n@docs Error, toString\n\n","unions":[{"name":"Error","comment":"","args":[],"cases":[["ErrorMessage",["String.String"]],["PlatformAccessError",["Shikensu.Path.Path Shikensu.Path.Encapsulated","FileSystem.AccessError"]],["PlatformUnknownError",["FileSystem.UnknownFileSystemError"]]]}],"aliases":[],"values":[{"name":"toString","comment":"","type":"Shikensu.Error.Error -> String.String"}],"binops":[]},"Shikensu.Focus":{"name":"Shikensu.Focus","comment":"\n\n# Focus\n\n@docs Focus, toAbsolutePath\n\n","unions":[{"name":"Focus","comment":"","args":[],"cases":[["CurrentDirectory",[]],["Relative",["Shikensu.Path.Path Shikensu.Path.Directory"]],["Absolute",["Shikensu.Path.Path Shikensu.Path.Directory"]]]}],"aliases":[],"values":[{"name":"toAbsolutePath","comment":"","type":"{ cwd : Shikensu.Path.Path Shikensu.Path.Directory } -> Shikensu.Focus.Focus -> Shikensu.Path.Path Shikensu.Path.Directory"}],"binops":[]},"Shikensu.Path":{"name":"Shikensu.Path","comment":"\n\n# Paths\n\n@docs Path, Directory, File, Encapsulated, Kind\n\n\n# Creation\n\n@docs directory, file\n\n\n# POSIX\n\n@docs fromPosix, toPosix\n\n\n# Encapsulation\n\n@docs encapsulate\n\n\n# Functions\n\n@docs combine, kind, length, map, unwrap\n\n","unions":[{"name":"Directory","comment":" ๐Ÿ‘ป Directory\n","args":[],"cases":[]},{"name":"Encapsulated","comment":" ๐Ÿ‘ป Encapsulated\n","args":[],"cases":[]},{"name":"File","comment":" ๐Ÿ‘ป File\n","args":[],"cases":[]},{"name":"Kind","comment":" ","args":[],"cases":[["Directory",[]],["File",[]]]},{"name":"Path","comment":" Path type.\nThis is used with the [phantom ๐Ÿ‘ป types](#phantom-types).\n\n directoryPath : Path Directory\n filePath : Path File\n encapsulatedPath : Path Encapsulated\n\n","args":["kind"],"cases":[]}],"aliases":[],"values":[{"name":"combine","comment":" Combine a directory path and another path.\n\n","type":"Shikensu.Path.Path Shikensu.Path.Directory -> Shikensu.Path.Path kind -> Shikensu.Path.Path kind"},{"name":"directory","comment":" Create a directory path.\n\n directory [ \"Audio\", \"Playlists\" ]\n\n","type":"Array.Array String.String -> Shikensu.Path.Path Shikensu.Path.Directory"},{"name":"encapsulate","comment":" Encapsulate a path.\n","type":"Shikensu.Path.Path kind -> Shikensu.Path.Path Shikensu.Path.Encapsulated"},{"name":"file","comment":" Create a file path.\n\n file [ \"Document\", \"invoice.pdf\" ]\n\n","type":"Array.Array String.String -> Shikensu.Path.Path Shikensu.Path.File"},{"name":"fromPosix","comment":" Convert a POSIX formatted string to a path.\nThis will return a `Encapsulated` path. To get a path of the type `Path Directory` or `Path File`, use the functions in the `Webnative.Path.Encapsulated` module.\n\n >>> import Shikensu.Path.Encapsulated\n >>> \"foo/bar/\"\n ..> |> fromPosix\n ..> |> Shikensu.Path.Encapsulated.toDirectory\n Just (directory [ \"foo\", \"bar\" ])\n\n >>> \"foo/bar\"\n ..> |> fromPosix\n ..> |> Shikensu.Path.Encapsulated.toFile\n Just (file [ \"foo\", \"bar\" ])\n\n","type":"String.String -> Shikensu.Path.Path Shikensu.Path.Encapsulated"},{"name":"kind","comment":" Get the path kind.\n\n >>> kind (directory [])\n Directory\n >>> kind (file [])\n File\n\nEven if a path is encapsulated,\nyou can still check the kind of path it is.\n\n >>> kind (encapsulate <| directory [])\n Directory\n >>> kind (encapsulate <| file [])\n File\n\n","type":"Shikensu.Path.Path kind -> Shikensu.Path.Kind"},{"name":"length","comment":" Length.\n","type":"Shikensu.Path.Path kind -> Basics.Int"},{"name":"map","comment":" Map.\n","type":"(Array.Array String.String -> Array.Array String.String) -> Shikensu.Path.Path kind -> Shikensu.Path.Path kind"},{"name":"toPosix","comment":" Convert a path to the POSIX format.\n\n >>> toPosix { absolute = True } (directory [ \"foo\", \"bar\"])\n \"/foo/bar/\"\n >>> toPosix { absolute = False } (file [ \"foo\", \"bar\"])\n \"foo/bar\"\n\n","type":"{ absolute : Basics.Bool } -> Shikensu.Path.Path kind -> String.String"},{"name":"unwrap","comment":" Get the path parts.\n\n >>> unwrap (directory [ \"foo\", \"bar\" ])\n [ \"foo\", \"bar\" ]\n >>> unwrap (file [ \"foo\", \"bar\" ])\n [ \"foo\", \"bar\" ]\n\n","type":"Shikensu.Path.Path kind -> Array.Array String.String"}],"binops":[]},"Shikensu.Path.Encapsulated":{"name":"Shikensu.Path.Encapsulated","comment":"\n\n# Encapsulated Paths\n\n@docs toDirectory, toFile\n\n","unions":[],"aliases":[],"values":[{"name":"toDirectory","comment":" Remove the membrane and extract a `Path Directory`.\n","type":"Shikensu.Path.Path Shikensu.Path.Encapsulated -> Maybe.Maybe (Shikensu.Path.Path Shikensu.Path.Directory)"},{"name":"toFile","comment":" Remove the membrane and extract a `Path File`.\n","type":"Shikensu.Path.Path Shikensu.Path.Encapsulated -> Maybe.Maybe (Shikensu.Path.Path Shikensu.Path.File)"}],"binops":[]}} \ No newline at end of file diff --git a/gren.json b/gren.json index 05d3721..eebed4a 100644 --- a/gren.json +++ b/gren.json @@ -4,7 +4,7 @@ "name": "icidasset/shikensu-gren", "summary": "Run a sequence of functions on in-memory representations of files", "license": "BSD-3-Clause", - "version": "3.0.0", + "version": "4.0.0", "exposed-modules": [ "Shikensu", "Shikensu.Bundle", diff --git a/src/Shikensu.gren b/src/Shikensu.gren index 9fee607..3c74d49 100644 --- a/src/Shikensu.gren +++ b/src/Shikensu.gren @@ -1,16 +1,21 @@ -module Shikensu exposing ( Program, Task, list, perform, program, programs, read, write, writeDefinition ) +module Shikensu exposing ( Program, Task, currentWorkingDirectory, list, perform, program, programs, read, write, writeDefinition ) {-| # ๐Ÿš€ -@docs program, programs, Program, list, perform, Task +@docs program, programs, Program, Task, list, perform # IO @docs read, write, writeDefinition + +# ๐Ÿ› ๏ธ + +@docs currentWorkingDirectory + -} import Bytes.Encode @@ -153,8 +158,7 @@ If you run `./binary/app` the resulting path will be `~/code/example/`. list : FileSystem.Permission -> Focus -> Task list fsPermission focus = fsPermission - |> Path.currentWorkingDirectory - |> Task.mapError neverError + |> currentWorkingDirectory |> Task.andThen (\cwd -> let @@ -327,12 +331,28 @@ writeDefinition permission destinationDirectory def = --- ใŠ™๏ธ +-- ๐Ÿ› ๏ธ + + +{-| Get the absolute directory path of the current working directory. +-} +currentWorkingDirectory : FileSystem.Permission -> Task.Task Error (Path Directory) +currentWorkingDirectory permission = + permission + |> FileSystem.currentWorkingDirectory + |> Task.map + (\a -> + if String.endsWith "/" a then + a + else + a ++ "/" + ) + |> Task.map (Path.fromPosix >> Path.unwrap >> Path.directory) + |> Task.mapError (\_ -> ErrorMessage "Never ever have I ๐Ÿคซ") -neverError : Never -> Error -neverError _ = - ErrorMessage "Never ever have I ๐Ÿคซ" + +-- ใŠ™๏ธ recursiveList : FileSystem.Permission -> Path Directory -> Path Directory -> Task.Task Error (Array Definition) diff --git a/src/Shikensu/Path.gren b/src/Shikensu/Path.gren index 72588c9..343f805 100644 --- a/src/Shikensu/Path.gren +++ b/src/Shikensu/Path.gren @@ -1,4 +1,4 @@ -module Shikensu.Path exposing ( Path, Directory, File, Encapsulated, Kind(..), currentWorkingDirectory, directory, length, file, fromPosix, toPosix, encapsulate, combine, kind, map, unwrap ) +module Shikensu.Path exposing ( Path, Directory, File, Encapsulated, Kind(..), directory, length, file, fromPosix, toPosix, encapsulate, combine, kind, map, unwrap ) {-| @@ -9,7 +9,7 @@ module Shikensu.Path exposing ( Path, Directory, File, Encapsulated, Kind(..), c # Creation -@docs directory, file, currentWorkingDirectory +@docs directory, file # POSIX @@ -28,8 +28,6 @@ module Shikensu.Path exposing ( Path, Directory, File, Encapsulated, Kind(..), c -} -import FileSystem -import Task exposing ( Task ) {-| Path type. @@ -96,22 +94,6 @@ file = Path File -{-| Get the absolute directory path of the current working directory. --} -currentWorkingDirectory : FileSystem.Permission -> Task Never (Path Directory) -currentWorkingDirectory permission = - permission - |> FileSystem.currentWorkingDirectory - |> Task.map - (\a -> - if String.endsWith "/" a then - a - else - a ++ "/" - ) - |> Task.map (fromPosix >> unwrap >> directory) - - -- POSIX