{"id":26076854,"url":"https://github.com/purescript-contrib/purescript-pathy","last_synced_at":"2026-01-27T08:02:05.228Z","repository":{"id":31209525,"uuid":"34770522","full_name":"purescript-contrib/purescript-pathy","owner":"purescript-contrib","description":"A type-safe abstraction for platform-independent file system paths.","archived":false,"fork":false,"pushed_at":"2022-04-27T22:32:47.000Z","size":200,"stargazers_count":32,"open_issues_count":2,"forks_count":16,"subscribers_count":10,"default_branch":"main","last_synced_at":"2026-01-11T16:20:28.212Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"PureScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/purescript-contrib.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-04-29T03:32:59.000Z","updated_at":"2025-08-20T13:19:20.000Z","dependencies_parsed_at":"2022-07-22T04:31:54.826Z","dependency_job_id":null,"html_url":"https://github.com/purescript-contrib/purescript-pathy","commit_stats":null,"previous_names":["slamdata/purescript-pathy"],"tags_count":26,"template":false,"template_full_name":null,"purl":"pkg:github/purescript-contrib/purescript-pathy","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/purescript-contrib%2Fpurescript-pathy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/purescript-contrib%2Fpurescript-pathy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/purescript-contrib%2Fpurescript-pathy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/purescript-contrib%2Fpurescript-pathy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/purescript-contrib","download_url":"https://codeload.github.com/purescript-contrib/purescript-pathy/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/purescript-contrib%2Fpurescript-pathy/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28809333,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-27T07:41:26.337Z","status":"ssl_error","status_checked_at":"2026-01-27T07:41:08.776Z","response_time":168,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-03-09T02:36:26.892Z","updated_at":"2026-01-27T08:02:05.175Z","avatar_url":"https://github.com/purescript-contrib.png","language":"PureScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Pathy\n\n[![CI](https://github.com/purescript-contrib/purescript-pathy/workflows/CI/badge.svg?branch=main)](https://github.com/purescript-contrib/purescript-pathy/actions?query=workflow%3ACI+branch%3Amain)\n[![Release](https://img.shields.io/github/release/purescript-contrib/purescript-pathy.svg)](https://github.com/purescript-contrib/purescript-pathy/releases)\n[![Pursuit](https://pursuit.purescript.org/packages/purescript-pathy/badge)](https://pursuit.purescript.org/packages/purescript-pathy)\n[![Maintainer: garyb](https://img.shields.io/badge/maintainer-garyb-teal.svg)](https://github.com/garyb)\n\nA type-safe abstraction for platform-independent file system paths.\n\n## Installation\n\nInstall `pathy` with [Spago](https://github.com/purescript/spago):\n\n```sh\nspago install pathy\n```\n\n## Quick start\n\nApplications often have to refer to file system paths in a platform-independent way.\n\nMany path libraries provide a single abstraction to deal with file system paths. This allows easy composition of different kinds of paths, but comes at the expense of the following distinctions:\n\n * The distinction between relative and absolute paths.\n * The distinction between paths denoting file resources and paths denoting directories.\n\nPathy also uses a single abstraction for file system paths, called `Path`, but uses *phantom types* to keep track of the above distinctions.\n\nThis approach lets you write code that performs type-safe composition of relative, absolute, file, and directory paths, and makes sure you never use paths in an unsafe fashion. Bogus and insecure operations simply aren't allowed by the type system!\n\nMany paths come from user-input or configuration data. Pathy can parse such string paths and allow you to safely resolve them to expected types.\n\n### Paths Literals\n\nBuilding path literals is easy using the following components:\n\n * `rootDir` – The root directory of an absolute path.\n * `currentDir` – The current directory (AKA the \"working directory\"), useful for building relative paths.\n * `file` – A file (in the current directory).\n * `dir` – A directory (in the current directory).\n * `(\u003c/\u003e)` – Adds a relative path to the end of a (relative or absolute) path.\n * `(\u003c.\u003e)` – Sets the extension of a file path.\n * `(\u003c..\u003e)` – Ascends one level in a directory, then descends into the specified relative path.\n\nAll path segments (`file` / `dir`) names are required to be non-empty. This is enforced by `Name` being constructed from a `NonEmptyString`. At compile time, we can have provably non-empty strings by using `Symbol`s and a bit of type class trickery:\n\n``` purescript\ndirFoo :: Name Dir\ndirFoo = dir (SProxy :: SProxy \"foo\")\n```\n\nHere we're using a symbol proxy (`SProxy`) and then typing it to explicitly carry the name that we want to use for our path at runtime. There is also a `dir'` and `file'` variation on the function that accepts normal `Name` values, so if you are not constructing a path at compile-time, you'd be using these instead.\n\nSome example compile-time path constructions:\n\n```purescript\npath1 = rootDir \u003c/\u003e dir (SProxy :: SProxy \"foo\") \u003c/\u003e dir (SProxy :: SProxy \"bar\") \u003c/\u003e file (SProxy :: SProxy \"baz.boo\")\npath2 = currentDir \u003c/\u003e dir (SProxy :: SProxy \"foo\")\n```\n\nThanks to the phantom type parameters, Pathy doesn't let you create path combinations that don't make sense. The following examples will be rejected at compile time:\n\n```purescript\nrootDir \u003c/\u003e rootDir\ncurrentDir \u003c/\u003e rootDir\nfile (SProxy :: SProxy \"foo\") \u003c/\u003e file (SProxy :: SProxy \"bar\")\nfile (SProxy :: SProxy \"foo\") \u003c/\u003e dir (SProxy :: SProxy \"bar\")\n```\n\n### The Path Type\n\nThe `Path a b` type has two type parameters:\n\n * `a` – This may be `Abs` or `Rel`, indicating whether the path is absolute or relative.\n * `b` – This may be `Dir` or `File`, indicating whether the path is a file or directory.\n\nYou should try to make the `Path` functions that you write as generic as possible. If you have a function that only cares if a path refers to a file, then you can write it like this:\n\n```purescript\nmyFunction :: forall a. Path a File -\u003e ...\nmyFunction p = ...\n```\n\nBy universally quantifying over the type parameters you don't care about, you ensure your code will work with the most paths possible (you also are documenting the expectations of your function to other developers who read your code).\n\n### Parse Paths from Strings\n\nTo parse a string into a `Path`, you can use the `parsePath` function, which expects you to handle four cases:\n\n * `Path Rel File`\n * `Path Abs File`\n * `Path Rel Dir`\n * `Path Abs Dir`\n\nIf you need a specific case, you can use helper functions such as `parseRelFile`, which return a `Maybe`.\n\nThe `parsePath` function also expects a `Parser` argument so that different path formats can be parsed into the common `Path` type.\n\n### Sandboxing\n\nPathy makes it easy to create relative paths, even paths that ascend into parent directories of relative paths. With this power comes danger: if you parse a user string, the user may be able to escape any arbitrary directory.\n\nPathy solves this security problem by *disallowing* conversion from a `Path` to a `String` until the `Path` has been *sandboxed*.\n\nTo sandbox a path, you just call `sandbox` and provide the sandbox directory, as well as the path to sandbox:\n\n```purescript\nsandbox\n  (rootDir \u003c/\u003e dir (SProxy :: SProxy \"foo\")) -- sandbox root\n  (rootDir \u003c/\u003e dir (SProxy :: SProxy \"foo\") \u003c/\u003e dir (SProxy :: SProxy \"bar\")) -- path to sandbox\n```\n\nThis returns a `Maybe`, which is `Nothing` if the tainted path escapes the sandbox.\n\nAfter you have sandboxed a foreign path, you may call `printPath` on it, which will print the path absolutely.\n\nThere is also the option to `unsafePrintPath`. This is labelled as being unsafe as it may be depending on how it is used - for example, if a path was sandboxed against some path other than the current working directory, but then used when launching a command in the current working directory, it may still refer to a location that it should not have access to.\n\n### Renaming, Transforming, Etc.\n\nThere are many other functions available to you for renaming files, renaming directories, getting parent directories, etc.\n\nThese are all documented [on Pursuit](http://pursuit.purescript.org/packages/purescript-pathy), and you can find [test usages](/test/Main.purs) for most of them.\n\n## Documentation\n\n`pathy` documentation is stored in a few places:\n\n1. Module documentation is [published on Pursuit](https://pursuit.purescript.org/packages/purescript-pathy).\n2. Usage examples can be found in [the test suite](./test).\n\nIf you get stuck, there are several ways to get help:\n\n- [Open an issue](https://github.com/purescript-contrib/purescript-pathy/issues) if you have encountered a bug or problem.\n- Ask general questions on the [PureScript Discourse](https://discourse.purescript.org) forum or the [PureScript Discord](https://purescript.org/chat) chat.\n\n## Contributing\n\nYou can contribute to `pathy` in several ways:\n\n1. If you encounter a problem or have a question, please [open an issue](https://github.com/purescript-contrib/purescript-pathy/issues). We'll do our best to work with you to resolve or answer it.\n\n2. If you would like to contribute code, tests, or documentation, please [read the contributor guide](./CONTRIBUTING.md). It's a short, helpful introduction to contributing to this library, including development instructions.\n\n3. If you have written a library, tutorial, guide, or other resource based on this package, please share it on the [PureScript Discourse](https://discourse.purescript.org)! Writing libraries and learning resources are a great way to help this library succeed.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpurescript-contrib%2Fpurescript-pathy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpurescript-contrib%2Fpurescript-pathy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpurescript-contrib%2Fpurescript-pathy/lists"}