dennisdoomen / dennisdoomen/pathy
[API Proposal]: IsUnder and Contains for safe ancestor checks
- Dominant language
- C#
- Stars
- 27
- Forks
- 5
- Avg merge
- 21h 29m
- Merged PRs (30d)
- 10
Description
### Background and motivation
Checking whether one path lives underneath another is one of the most common path operations, and one of the easiest to get wrong. The naive `a.ToString().StartsWith(b.ToString())` approach reports that `c:\foobar` is under `c:\foo`, and it also breaks on trailing separators and on mixed casing. Pathy already normalises separators and knows about rooting, so it is the right place to offer a correct implementation.
### API Proposal
```C#
namespace Pathy
{
public readonly struct ChainablePath
{
public bool IsUnder(ChainablePath other);
public bool Contains(ChainablePath other);
}
}
```
`IsUnder` returns `true` when this path is a strict descendant of `other`. `Contains` is the inverse, so it reads naturally from the directory side.
### API Usage
```C#
var repo = ChainablePath.From("c:/work/repo");
(repo / "src" / "Program.cs").IsUnder(repo); // true
(ChainablePath.From("c:/work/repository")).IsUnder(repo); // false, not just a string prefix
repo.Contains(repo / "src"); // true
repo.IsUnder(repo); // false, a path is not under itself
```
A typical use is guarding against path traversal after combining an untrusted segment:
```C#
var target = uploadRoot / userSuppliedName;
if (!target.IsUnder(uploadRoot))
{
throw new SecurityException("Path escapes the upload root.");
}
```
### Alternative Designs
* Only offer `IsUnder` and let callers flip the operands. `Contains` is cheap to add and makes guard clauses read better.
* Add an `includeSelf` parameter instead of fixing the strict-descendant semantics. A separate `Equals` check is clearer.
### Risks
The comparison needs a documented decision on case sensitivity. Matching the behaviour of the current `Equals` implementation keeps this consistent. Both paths should be normalised (and ideally made absolute) before comparison, otherwise the result depends on the current working directory.
Contributor guide
Research direction
Start by locating ChainablePath and its current Equals implementation, then review how Pathy normalises separators and handles rooted paths. Confirm the case-sensitivity and absolute-path decisions against Equals. Done means IsUnder provides strict descendant checks, Contains is its inverse, and the documented examples distinguish path boundaries correctly.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- csharp
- Domain
- tooling
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100