StrictPath.Core 0.1.1

dotnet add package StrictPath.Core --version 0.1.1
                    
NuGet\Install-Package StrictPath.Core -Version 0.1.1
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="StrictPath.Core" Version="0.1.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="StrictPath.Core" Version="0.1.1" />
                    
Directory.Packages.props
<PackageReference Include="StrictPath.Core" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add StrictPath.Core --version 0.1.1
                    
#r "nuget: StrictPath.Core, 0.1.1"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package StrictPath.Core@0.1.1
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=StrictPath.Core&version=0.1.1
                    
Install as a Cake Addin
#tool nuget:?package=StrictPath.Core&version=0.1.1
                    
Install as a Cake Tool

StrictPath

An immutable, strict path/file API for .NET 10. One class — SPath — wraps an absolute path and makes risky operations explicit: writes never overwrite existing files unless you pass overwrite: true, and the guarantee is enforced atomically at the OS level (FileMode.CreateNew), not by a check-then-write race.

Works on Windows, macOS, and Linux (see Cross-platform behavior).

This is a monorepo with three packages:

Project What it is
StrictPath.Core TheSPath type: path algebra, assertions, strict I/O (sync + async, System.Text.Json).
StrictPath.Json ReadNewtonsoftJson / WriteNewtonsoftJson extensions (Newtonsoft.Json).
StrictPath.Zip ZipFrom / Unzip extensions (SharpZipLib) with portable entry names and zip-slip protection.

Quick start

using StrictPath;

var root = new SPath("data").Create();            // mkdir -p data
var file = root / "config.json";                  // join with '/'

file.WriteJson(new { Port = 8080 }, indent: true);        // throws if file exists
file.WriteJson(new { Port = 9090 }, overwrite: true);     // explicit overwrite

var cfg = file.ReadJson<Dictionary<string, int>>();       // System.Text.Json
await file.WriteTextAsync("...", overwrite: true);        // async variants throughout

var backup = root.Join("backup").Create();
var copied = file.CopyIn(backup);                 // backup/config.json
copied.MoveTo(backup / "old.json");

foreach (var f in root.FilesDeep())               // recursive file listing
    Console.WriteLine(f.RelativeTo(root));

Design principles

  1. Immutable. SPath is a value: every transformation (Join, WithExtension, Parent, ToReal) returns a new instance. Instances are safe to share and compare (IEquatable<SPath>, ==, hashable).
  2. Strict by construction. Every write opens the file with FileMode.CreateNew unless overwrite: true is passed, so "never clobber by accident" holds even against concurrent writers.
  3. Destruction is named at the call site. The only ways to lose data are Delete(), overwrite: true, and ExistingFile.Overwrite — there is no hidden overwrite state to arm or forget, and no convenience method that quietly bundles a delete.
  4. One exception type. Every violated expectation throws StrictPathException with a message naming the path. It derives from IOException, so existing catch (IOException) handlers still work.
  5. Properties are cheap, methods do work. Exists/IsFile/IsDirectory are properties; anything that reads file contents or walks directories is a method (GetSize(), GetCrc32(), GetRealPath(), Files(), …).

API overview

Path algebra (pure, no disk access)

Member Meaning
new SPath(path) Normalizes to an absolute path (Path.GetFullPath).
Join(...) / a / "sub" Combine paths.
WithExtension(".txt") Replace the extension (""/null removes it; must start with .).
AppendExtension(".zip") file.jsonfile.json.zip
Name, Stem, Extension, Parent dir/file.jsonfile.json, file, .json, dir
RelativeTo(ancestor) Relative path string fromancestor.
ToString() ReturnsFullPath; never touches the disk.

Queries

IsFile, IsDirectory, Exists, Optional() — existence. GetSize(), GetCrc32() — file facts. Children(), Files(), Directories(), FilesDeep(), Glob(pattern) — enumeration; all require the path to be a directory and throw otherwise. Glob matches files only. GetRealPath() / ToReal() — the exact on-disk casing (see below).

Assertions

AssertFile(), AssertDirectory(), AssertExists(), AssertNotExists(), AssertExtension(".json"), AssertDescendantOf(dir), AssertSubpathOf(dir). All throw StrictPathException on failure and return this for chaining. The containment assertions are purely lexical (no disk access, symlinks not resolved).

I/O — strict by default

ReadText, ReadBytes, ReadJson<T>, OpenText and WriteText, WriteBytes, WriteJson, OpenWrite — each write takes overwrite: false by default; each has an Async variant (except Open*, whose streams support async I/O directly).

file.WriteText("v1");                    // ok, file is new
file.WriteText("v2");                    // StrictPathException
file.WriteText("v2", overwrite: true);   // ok — explicit, this call only
file.Delete().CreateParents().WriteText("v3");   // destruction spelled out, by name

Operations

Create(), CreateParents(), CreateTmp(parent?), CreateAsJson(), Delete(recursive?) (idempotent), MoveTo / MoveFrom, CopyIn / CopyContents / CopyFrom — all take overwrite: false by default; a move never replaces an existing directory.

Zip (StrictPath.Zip)

using StrictPath.Zip;

var zip = new SPath("data.zip").ZipFrom(folder);          // zip a folder
zip.Unzip();                                              // throws on existing files (default)
zip.Unzip(target, ExistingFile.Skip);                     // or Skip / Overwrite
  • Entry names always use / (zip spec), so Windows-created archives extract correctly everywhere.
  • Extraction rejects zip slip (entries with .. or absolute names) with StrictPathException, and normalizes \ entries from legacy Windows tools.
  • Only files are stored; empty directories produce no entries.

Newtonsoft JSON (StrictPath.Json)

using StrictPath.Json;

file.WriteNewtonsoftJson(obj, indent: true);          // strict, like every write
var value = file.ReadNewtonsoftJson<MyType>();

Cross-platform behavior

  • Separators/ and \ both accepted on Windows; produced paths use the platform separator.
  • EqualitySPath.PathComparison: ordinal case-insensitive on Windows/macOS, ordinal case-sensitive on Linux, matching each platform's default file-system semantics.
  • GetRealPath() — returns the exact on-disk casing; handles drive roots (C:\), UNC shares (\\server\share), and the Unix root (/). When both foo and FOO exist (case-sensitive file systems), each resolves to itself.
  • ExtensionsAssertExtension is case-insensitive (.json == .JSON) on every platform.
  • CreateTmp() — creates a randomly-named tmp_xxxxxxxx directory under the current working directory by default (not the system temp dir); random names keep concurrent callers from colliding.
  • CI.github/workflows/ci.yml runs the suite on Linux, Windows, and macOS; the case-sensitivity tests only execute on Linux.

Building and testing

dotnet test StrictPath.slnx     # requires the .NET 10 SDK

Publishing to nuget.org

Pushing a version tag packs all three packages with that version and publishes them via the publish job in ci.yml:

git tag v1.0.0 && git push origin v1.0.0

Publishing uses nuget.org Trusted Publishing (OIDC) — no stored API key.

License

MIT

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (2)

Showing the top 2 NuGet packages that depend on StrictPath.Core:

Package Downloads
StrictPath.Zip

Zip/unzip extension methods for StrictPath's SPath, with portable entry names and zip-slip protection.

StrictPath.Json

Newtonsoft.Json extension methods for StrictPath's SPath.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.1.1 119 8/10/2026
0.1.0 113 8/10/2026