ModelingEvolution.FileSystem 2.1.0

There is a newer version of this package available.
See the version list below for details.
dotnet add package ModelingEvolution.FileSystem --version 2.1.0
                    
NuGet\Install-Package ModelingEvolution.FileSystem -Version 2.1.0
                    
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="ModelingEvolution.FileSystem" Version="2.1.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="ModelingEvolution.FileSystem" Version="2.1.0" />
                    
Directory.Packages.props
<PackageReference Include="ModelingEvolution.FileSystem" />
                    
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 ModelingEvolution.FileSystem --version 2.1.0
                    
#r "nuget: ModelingEvolution.FileSystem, 2.1.0"
                    
#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 ModelingEvolution.FileSystem@2.1.0
                    
#: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=ModelingEvolution.FileSystem&version=2.1.0
                    
Install as a Cake Addin
#tool nuget:?package=ModelingEvolution.FileSystem&version=2.1.0
                    
Install as a Cake Tool

ModelingEvolution.FileSystem

NuGet

Strongly-typed file system path handling for .NET with intuitive path arithmetic operators.

Features

  • Type-safe paths: AbsolutePath, RelativePath, and FileExtension value types
  • Path arithmetic: Intuitive operators for combining and computing paths
  • Cross-platform: Automatically normalizes separators to current platform (/ on Linux, \ on Windows)
  • Pure value types: No filesystem access - paths are just data
  • IParsable support: Works with Parse, TryParse, and generic parsing APIs
  • JSON serialization: Built-in System.Text.Json support via JsonParsableConverter

Installation

dotnet add package ModelingEvolution.FileSystem

Quick Start

using ModelingEvolution.FileSystem;

// Create paths (implicit conversion from string)
AbsolutePath projectRoot = "/home/user/projects/myapp";  // Linux
AbsolutePath projectRoot = @"C:\Projects\MyApp";         // Windows

RelativePath srcFolder = "src/components";

// Combine paths with + operator
AbsolutePath fullPath = projectRoot + srcFolder;
// Linux:   /home/user/projects/myapp/src/components
// Windows: C:\Projects\MyApp\src\components

// Get relative path between absolutes with - operator
RelativePath relative = fullPath - projectRoot;
// Result: src/components (or src\components on Windows)

Path Arithmetic Operators

Expression Result Description
Relative + Relative RelativePath Combine two relative paths
Absolute + Relative AbsolutePath Append relative path to absolute
Absolute - Absolute RelativePath Get relative path between two absolutes

Examples

// Relative + Relative = Relative
RelativePath src = "src";
RelativePath components = "components";
RelativePath combined = src + components;  // src/components

// Absolute + Relative = Absolute
AbsolutePath root = "/projects";
AbsolutePath full = root + combined;  // /projects/src/components

// Absolute - Absolute = Relative
AbsolutePath from = "/projects/app";
AbsolutePath to = "/projects/app/src/utils";
RelativePath diff = to - from;  // src/utils

// Works with parent traversal
AbsolutePath sibling = "/projects/other";
RelativePath toSibling = sibling - from;  // ../other

Cross-Platform Path Normalization

Paths are automatically normalized to the current platform's separator:

// On Linux - all separators become /
RelativePath path = "foo\\bar/baz";
Console.WriteLine((string)path);  // foo/bar/baz

// On Windows - all separators become \
RelativePath path = "foo\\bar/baz";
Console.WriteLine((string)path);  // foo\bar\baz

Mixed and duplicate separators are handled:

RelativePath path = "foo//bar\\\\baz";
// Normalized to: foo/bar/baz (Linux) or foo\bar\baz (Windows)

API Reference

RelativePath

public readonly record struct RelativePath : IParsable<RelativePath>, IComparable<RelativePath>
{
    // Construction
    public RelativePath(string path);
    public static readonly RelativePath Empty;

    // Properties
    public bool IsEmpty { get; }
    public RelativePath FileName { get; }
    public RelativePath FileNameWithoutExtension { get; }
    public FileExtension Extension { get; }
    public RelativePath Parent { get; }
    public string[] Segments { get; }

    // Methods
    public RelativePath ChangeExtension(FileExtension newExtension);

    // Operators
    public static RelativePath operator +(RelativePath left, RelativePath right);
    public static RelativePath operator +(RelativePath left, string right);

    // Conversions (use these instead of .Value)
    public static implicit operator RelativePath(string path);
    public static implicit operator string(RelativePath path);
}

AbsolutePath

public readonly record struct AbsolutePath : IParsable<AbsolutePath>, IComparable<AbsolutePath>
{
    // Construction
    public AbsolutePath(string path);

    // Properties
    public RelativePath FileName { get; }
    public RelativePath FileNameWithoutExtension { get; }
    public FileExtension Extension { get; }
    public AbsolutePath? Root { get; }
    public AbsolutePath? Parent { get; }

    // Methods
    public AbsolutePath ChangeExtension(FileExtension newExtension);
    public bool StartsWith(AbsolutePath basePath);

    // Operators
    public static AbsolutePath operator +(AbsolutePath left, RelativePath right);
    public static AbsolutePath operator +(AbsolutePath left, string right);
    public static RelativePath operator -(AbsolutePath right, AbsolutePath left);

    // Conversions (use these instead of .Value)
    public static implicit operator AbsolutePath(string path);
    public static implicit operator string(AbsolutePath path);
}

FileExtension

public readonly record struct FileExtension : IParsable<FileExtension>, IComparable<FileExtension>
{
    // Construction
    public FileExtension(string extension);
    public static readonly FileExtension None;

    // Properties
    public bool IsEmpty { get; }
    public string WithDot { get; }      // ".txt"
    public string WithoutDot { get; }   // "txt"

    // Common extensions
    public static FileExtension Txt { get; }
    public static FileExtension Json { get; }
    public static FileExtension Cs { get; }
    public static FileExtension Md { get; }
    // ... and more

    // Methods
    public bool IsOneOf(params FileExtension[] extensions);
    public bool IsOneOf(params string[] extensions);

    // Conversions
    public static implicit operator FileExtension(string extension);
    public static implicit operator string(FileExtension extension);
}

JSON Serialization

All types serialize as strings:

using System.Text.Json;

var config = new AppConfig
{
    ProjectRoot = (AbsolutePath)"/projects/myapp",
    SourceFolder = (RelativePath)"src/main",
    OutputExtension = FileExtension.Json
};

string json = JsonSerializer.Serialize(config);
// {"ProjectRoot":"/projects/myapp","SourceFolder":"src/main","OutputExtension":".json"}

Use Cases

Building file paths safely

AbsolutePath outputDir = (AbsolutePath)config.BuildOutput;
RelativePath artifactPath = (RelativePath)"bin" + config.Configuration + config.TargetFramework;
AbsolutePath fullOutput = outputDir + artifactPath;

Working with extensions

RelativePath file = "document.txt";
if (file.Extension.IsOneOf(".txt", ".md", ".rst"))
{
    // Handle text files
    var newFile = file.ChangeExtension(".html");
}
AbsolutePath docFile = (AbsolutePath)"/docs/api/classes/MyClass.md";
AbsolutePath imageFile = (AbsolutePath)"/docs/images/diagram.png";
RelativePath relativeLink = imageFile - docFile.Parent!.Value;
// Result: ../../images/diagram.png

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 ModelingEvolution.FileSystem:

Package Downloads
ModelingEvolution.Ide

Package Description

ModelingEvolution.FileSystem.Blazor

Blazor FileExplorer component with MudBlazor for browsing local file systems. Uses IFileSystem abstraction for all operations.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
2.2.0 0 1/26/2026
2.1.1 54 1/24/2026
2.1.0 30 1/24/2026
2.0.1 321 1/13/2026
2.0.0 84 1/13/2026
1.0.1 78 1/13/2026
1.0.0 72 1/13/2026