{"id":16661202,"url":"https://github.com/sellout/dhall-path","last_synced_at":"2025-08-25T21:05:33.208Z","repository":{"id":194430050,"uuid":"690818049","full_name":"sellout/dhall-path","owner":"sellout","description":"Well-typed path manipulation for Dhall","archived":false,"fork":false,"pushed_at":"2025-08-03T05:55:37.000Z","size":72,"stargazers_count":4,"open_issues_count":1,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-08-03T07:18:42.105Z","etag":null,"topics":["dhall","filesystem","library"],"latest_commit_sha":null,"homepage":"https://sellout.github.io/dhall-path","language":"Dhall","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sellout.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":"sellout","patreon":"sellout"}},"created_at":"2023-09-13T00:16:45.000Z","updated_at":"2025-08-03T05:54:52.000Z","dependencies_parsed_at":null,"dependency_job_id":"ad617127-6e82-42cb-905f-acad8fb24be3","html_url":"https://github.com/sellout/dhall-path","commit_stats":null,"previous_names":["sellout/dhall-path"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/sellout/dhall-path","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sellout%2Fdhall-path","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sellout%2Fdhall-path/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sellout%2Fdhall-path/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sellout%2Fdhall-path/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sellout","download_url":"https://codeload.github.com/sellout/dhall-path/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sellout%2Fdhall-path/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":272131794,"owners_count":24878986,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-25T02:00:12.092Z","response_time":1107,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["dhall","filesystem","library"],"created_at":"2024-10-12T10:34:10.237Z","updated_at":"2025-08-25T21:05:33.194Z","avatar_url":"https://github.com/sellout.png","language":"Dhall","funding_links":["https://github.com/sponsors/sellout","https://patreon.com/sellout"],"categories":[],"sub_categories":[],"readme":"# Paths (for Dhall)\n\n[![built with garnix](https://img.shields.io/endpoint?url=https%3A%2F%2Fgarnix.io%2Fapi%2Fbadges%2Fsellout%2Fdhall-path)](https://garnix.io/repo/sellout/dhall-path)\n\nWell-typed path manipulation for Dhall\n\nA path library for Dhall, with various type-level guarantees.\n\n```dhall\n  let emacsDir =\n        Dir.descendThrough Anchor.Abs Dir.root [ \"usr\", \"share\", \"emacs\" ]\n  in  Dir.Absolute.toText Path.Format.POSIX emacsDir\n≡ \"/usr/share/emacs/\"\n```\n\nThis library offers two primary path types\n\n- `Path \u003c Abs | Rel \u003e \u003c Dir | File \u003e` and\n- `Path/Ambiguous \u003c Abs | Rel \u003e`.\n\n`Path` takes two type parameters, one indicating whether the path is absolute or relative (`Path/Anc`) and one indicating whether it’s a file or directory (`Path/Typ`). The latter only takes the `Path/Anc` parameter. Ambiguous paths can’t know whether they represent a file or directory. However, some operations (like `containing`) can bridge to non-ambiguous paths (since we know that regardless of what an ambiguous path represents, its containing path _must_ be a directory).\n\nThere are two other path representations, corresponding to the two above,\n\n- `Path/Any` and\n- `Path/Ambiguous/Any`.\n\nThese are structured the same as the primary ones, but don’t carry type information around. They’re mostly intended for interfacing with systems that don’t make those distinctions (for example, in Nix, basically all uses of paths accept any of the four possible `Path` structures, so it’s simpler to expose a single type covering all of them than a union of the distinct types). However, these are also used internally to simplify things like `toText`.\n\nThe stronger types of `Path` and `Path/Ambiguous` can always be recovered from the corresponding unanchored path type ([`Path/anchor`](./dhall/Path/anchor)), so operations are _only_ provided on “anchored” types, with the expectation of converting the type at interface boundaries as necessary.\n\nThere are also aliases for full and partial applications of `Path/Anchored`. Operations are defined for the most specific types possible, for example, `Directory/Absolute/isRoot`, not `Directory/isRoot` or `Path/isRoot`. Sometimes (like `isRoot`), this is because the function is undecidable in other cases. Without access to the file system, we can’t determine whether “../../../” is the root directory or not.\n\nThis type DAG[^1] not only shows all the aliases, but lists some operations (the labeled, dotted edges) that move between otherwise unconnected types. This isn’t a full diagram of the operations on paths, or even the subset of unary operations.\n\n![type diagram](./type-diagram.png)\n\nThe only failure cases in this library is when some relative path has too much re-parenting (“../”) relative to some other path such that the operation is impossible. This is represented by a `None` result.\n\n## documentation\n\nAPI docs are on [GitHub Pages](https://sellout.github.io/dhall-path).\n\nThe [`package.dhall`](https://sellout.github.io/dhall-path/package.dhall.html) modules have high level docs and examples\n\n## future ideas\n\n### distinguish re-parented paths from relative paths?\n\nThis could reduce the scope of some failures. It’s also possible that some systems can’t directly express re-parenting, and they would be able to distinguish that at the type level.\n\n## internals\n\nStructurally, paths look like\n\n```dhall\nλ(ancType : Type) →\nλ(typType : Type) →\n  { --| If the path is relative, this is the number of levels up the\n    --  hierarchy to move before descending into the directories (i.e.,\n    --  “../”).\n    parents : ancType\n  , --| The directory components of the path in reverse order.\n    directories : List Text\n  , --| If the path represents a file, the name of the file.\n    file : typeType\n  }\n```\n\nwith one minor variation – `Ambiguous` paths call `file` `component` (because the ambiguity is that we don’t know whether that component represents a directory name or a file name).\n\nThe `directories` are stored in reverse order, to make the common operations of cons, tail, fold, etc. a bit more intuitive[^2]. `ancType` is `{}` for absolute paths, `Natural` for relative paths, and `Optional Natural` for un-anchored paths. Similarly, `typType` is `{}` for directories, `Text` for files, and `Optional Text` for un-anchored paths.\n\n[^2]: **TODO**: Perhaps switch to a non-reverse ordering, since Dhall’s types are structural, the ordering is exposed, even if we try to prevent users from seeing it. Keeping it consistent would be good to avoid confusion.\n\n## development environment\n\nWe recommend the following steps to make working in this repository as easy as possible.\n\n### `direnv allow`\n\nThis command ensures that any work you do within this repository happens within a consistent reproducible environment. That environment provides various debugging tools, etc. When you leave this directory, you will leave that environment behind, so it doesn’t impact anything else on your system.\n\n### `git config --local include.path ../.cache/git/config`\n\nThis will apply our repository-specific Git configuration to `git` commands run against this repository. It’s lightweight (you should definitely look at it before applying this command) – it does things like telling `git blame` to ignore formatting-only commits.\n\n## building \u0026 development\n\nEspecially if you are unfamiliar with the Dhall ecosystem, there is a Nix build (both with and without a flake). If you are unfamiliar with Nix, [Nix adjacent](...) can help you get things working in the shortest time and least effort possible.\n\n### if you have `nix` installed\n\n`nix build` will build and test the project fully.\n\n`nix develop` will put you into an environment where the traditional build tooling works. If you also have `direnv` installed, then you should automatically be in that environment when you're in a directory in this project.\n\n## comparisons\n\nOther projects similar to this one, and how they differ.\n\n### `path` \u0026 `pathy`\n\nThis library was inspired by the [Haskell](https://hackage.haskell.org/package/path) `path` library and the [PureScript](https://github.com/purescript-contrib/purescript-pathy) \u0026 [Scala](https://github.com/precog/scala-pathy) `pathy` libraries. However, it differs from them in several ways.\n\nFor one, it supports `../` (unlike Haskell’s `path`). Avoiding re-parenting does nothing to eliminate failure cases, it just shifts them to different places. Avoiding escaping some scope can be handled via a “chroot”-style approach, using `encapsulate`.\n\nBeing in Dhall, it can’t support parsing strings, so it can never convert `Text` to `Path`. Since they must be held in a structured format anyway (which is good, regardless), it means that there is no system-specific awareness outside of the `toText` operation.\n\nIt supports a notion of “ambiguous” paths that aren’t either directories or files. This is due to its need to act as an interface to arbitrary systems.\n\nSince Dhall can’t compare strings, we can’t identify or remove common prefixes. The closest approximation is `route`, which removes a prefix by re-parenting.\n\nThis library has no special handling of extensions.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsellout%2Fdhall-path","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsellout%2Fdhall-path","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsellout%2Fdhall-path/lists"}