diff --git a/README.md b/README.md
index d0778a3..6c57a99 100644
--- a/README.md
+++ b/README.md
@@ -76,7 +76,7 @@ Aside from the strict types, the following features are supported for the paths:
- `LocalPath::IsAbsolute` to check the path kind (since it supports both kinds);
- `LocalPath::IsPrefixOf` to check path prefixes;
- `LocalPath::RelativeTo` to get a relative part between two paths, if possible;
-- extension methods on `IPath`: `GetExtensionWithDot` and `GetExtensionWithoutDot` to get the file extension with or without the leading dot (note they will return `null` for paths with no extensions: this will allow you to distinguish between paths with empty extension aka ending with dot, and paths with no dot whatsoever).
+- extension methods on `IPath`: `GetExtensionWithDot` and `GetExtensionWithoutDot` to get the file extension with or without the leading dot (note that `GetExtensionWithDot` will behave differently for paths ending with dots and paths without dot at all, which allows to reconstruct such a file name from its part without extension and the "extension with dot").
Documentation
-------------
diff --git a/TruePath.Tests/PathExtensionsTests.cs b/TruePath.Tests/PathExtensionsTests.cs
index 507d1f8..0f67054 100644
--- a/TruePath.Tests/PathExtensionsTests.cs
+++ b/TruePath.Tests/PathExtensionsTests.cs
@@ -7,12 +7,13 @@ namespace TruePath.Tests;
public class PathExtensionsTests
{
[Theory]
+ [InlineData("..", ".")]
[InlineData("foo/bar.txt", ".txt")]
[InlineData("/foo/bar.txt", ".txt")]
- [InlineData("foo/bar.", "")]
- [InlineData("foo/bar", null)]
+ [InlineData("foo/bar.", ".")]
+ [InlineData("foo/bar", "")]
[InlineData(".gitignore", ".gitignore")]
- public void GetExtensionWithDotTests(string path, string? expected)
+ public void GetExtensionWithDotTests(string path, string expected)
{
IPath local = new LocalPath(path);
Assert.Equal(expected, local.GetExtensionWithDot());
@@ -24,12 +25,14 @@ public void GetExtensionWithDotTests(string path, string? expected)
}
[Theory]
+ [InlineData(".", "")]
+ [InlineData("..", "")]
[InlineData("foo/bar.txt", "txt")]
[InlineData("/foo/bar.txt", "txt")]
[InlineData("foo/bar.", "")]
- [InlineData("foo/bar", null)]
+ [InlineData("foo/bar", "")]
[InlineData(".gitignore", "gitignore")]
- public void GetExtensionWithoutDotTests(string path, string? expected)
+ public void GetExtensionWithoutDotTests(string path, string expected)
{
IPath l = new LocalPath(path);
Assert.Equal(expected, l.GetExtensionWithoutDot());
diff --git a/TruePath/PathExtensions.cs b/TruePath/PathExtensions.cs
index d7aeaa0..460c4ae 100644
--- a/TruePath/PathExtensions.cs
+++ b/TruePath/PathExtensions.cs
@@ -12,38 +12,30 @@ public static class PathExtensions
///
/// Gets the extension of the file name of the with the dot character.
/// For example, for the path file.txt, this method will return a string .txt.
- ///
- /// Note that this method will return null for paths without extensions, and will return an empty
- /// string for paths whose names end with a dot (even though it is an unusual path). This behavior allows to
- /// distinguish such paths.
- ///
/// File name entirely consisting of extension, such as .gitignore, is returned as-is.
///
- /// The extension of the file name of the path with the dot.
- ///
- public static string? GetExtensionWithDot(this IPath path)
- {
- var fileExtenstion = Path.GetExtension(path.FileName);
- if (string.IsNullOrEmpty(fileExtenstion) && !path.FileName.EndsWith('.'))
- return null;
- return fileExtenstion;
- }
+ /// The extension of the file name of the path with the dot character (if present).
+ ///
+ /// This method will return an empty string for paths without extensions, and will return a dot for paths whose
+ /// names end with a dot (even though it is an unusual path). This behavior allows to distinguish such paths,
+ /// and potentially reconstruct the file name from its part without the extension and the "extension with dot".
+ ///
+ public static string GetExtensionWithDot(this IPath path) =>
+ path.FileName.EndsWith('.') ? "." : Path.GetExtension(path.FileName);
///
/// Gets the extension of the file name of the without the dot character.
/// For example, for the path file.txt, this method will return a string txt.
///
- /// Note that this method will return null for paths without extensions, and will return an empty
- /// string for paths whose names end with a dot (even though it is an unusual path). This behavior allows to
- /// distinguish such paths.
- ///
- ///
/// File name entirely consisting of extension, such as .gitignore, is returned with its leading dot
/// trimmed.
///
///
- ///
- /// The extension of the file name of the path without the dot.
- ///
- public static string? GetExtensionWithoutDot(this IPath path) => GetExtensionWithDot(path)?.TrimStart('.');
+ /// The extension of the file name of the path without the dot.
+ ///
+ /// This method will return an empty string for paths without extensions and with empty extensions (ending with
+ /// dot, which may be unusual). This behavior doesn't allow to distinguish such paths using this method, to
+ /// reconstruct the original name from its name without extension and its extension without dot.
+ ///
+ public static string GetExtensionWithoutDot(this IPath path) => GetExtensionWithDot(path).TrimStart('.');
}