From ccbf3a18cb9c1ed31e4e397bddd40b7cd71494b7 Mon Sep 17 00:00:00 2001 From: rameel Date: Tue, 6 Aug 2024 13:38:22 +0500 Subject: [PATCH 1/8] Update FilePath --- Ramstack.FileProviders.Tests/FilePathTests.cs | 6 +- Ramstack.FileProviders/FileNode.cs | 6 +- Ramstack.FileProviders/FileNodeBase.cs | 4 +- Ramstack.FileProviders/Internal/FilePath.cs | 58 ++++++++++++++----- Ramstack.FileProviders/ZipFileProvider.cs | 4 +- 5 files changed, 56 insertions(+), 22 deletions(-) diff --git a/Ramstack.FileProviders.Tests/FilePathTests.cs b/Ramstack.FileProviders.Tests/FilePathTests.cs index 8fa84f0..6887be4 100644 --- a/Ramstack.FileProviders.Tests/FilePathTests.cs +++ b/Ramstack.FileProviders.Tests/FilePathTests.cs @@ -78,15 +78,15 @@ public void GetFullPath_Error(string path) => public bool IsNavigatesAboveRoot(string path) => FilePath.IsNavigatesAboveRoot(path); - [TestCase("/", ExpectedResult = null)] + [TestCase("/", ExpectedResult = "")] [TestCase("/dir", ExpectedResult = "/")] [TestCase("/dir/file", ExpectedResult = "/dir")] [TestCase("/dir/dir/", ExpectedResult = "/dir/dir")] [TestCase("dir/dir", ExpectedResult = "dir")] [TestCase("dir/dir/", ExpectedResult = "dir/dir")] - [TestCase("//", ExpectedResult = null)] - [TestCase("///", ExpectedResult = null)] + [TestCase("//", ExpectedResult = "")] + [TestCase("///", ExpectedResult = "")] [TestCase("//dir", ExpectedResult = "/")] [TestCase("///dir", ExpectedResult = "/")] [TestCase("////dir", ExpectedResult = "/")] diff --git a/Ramstack.FileProviders/FileNode.cs b/Ramstack.FileProviders/FileNode.cs index 2662855..65e7ad9 100644 --- a/Ramstack.FileProviders/FileNode.cs +++ b/Ramstack.FileProviders/FileNode.cs @@ -20,12 +20,12 @@ public sealed class FileNode : FileNodeBase /// /// Gets the string representing the extension part of the file. /// - public string Extension => Path.GetExtension(FullName); + public string Extension => FilePath.GetExtension(FullName); /// /// Gets the full path of the directory containing the file. /// - public string DirectoryName => FilePath.GetDirectoryName(FullName)!; + public string DirectoryName => FilePath.GetDirectoryName(FullName); /// /// Gets the last write time of the current file. @@ -39,7 +39,7 @@ public DirectoryNode Directory { get { - var path = FilePath.GetDirectoryName(FullName)!; + var path = FilePath.GetDirectoryName(FullName); var directory = Provider.GetDirectoryContents(path); return new DirectoryNode(Provider, path, directory); } diff --git a/Ramstack.FileProviders/FileNodeBase.cs b/Ramstack.FileProviders/FileNodeBase.cs index 3bee81f..fa98656 100644 --- a/Ramstack.FileProviders/FileNodeBase.cs +++ b/Ramstack.FileProviders/FileNodeBase.cs @@ -2,6 +2,8 @@ using Microsoft.Extensions.FileProviders; +using Ramstack.FileProviders.Internal; + namespace Ramstack.FileProviders; /// @@ -23,7 +25,7 @@ public abstract class FileNodeBase /// /// Gets the name of the file or directory. /// - public string Name => Path.GetFileName(FullName); + public string Name => FilePath.GetFileName(FullName); /// /// Gets a value indicating whether the file or directory exists. diff --git a/Ramstack.FileProviders/Internal/FilePath.cs b/Ramstack.FileProviders/Internal/FilePath.cs index 43af78d..7ca682a 100644 --- a/Ramstack.FileProviders/Internal/FilePath.cs +++ b/Ramstack.FileProviders/Internal/FilePath.cs @@ -15,33 +15,65 @@ internal static class FilePath private const int StackallocThreshold = 160; /// - /// Returns the directory portion of a file path. + /// Gets the extension part of the specified path string, including the leading dot . + /// even if it is the entire file name, or an empty string if no extension is present. /// - /// - /// Returns a string consisting of all characters up to but not including the last - /// forward slash (/) in the file path. The returned value is - /// if the specified path is a root (/). - /// - /// The path of a file or directory. + /// The path string from which to get the extension. /// - /// Directory information for path, or if path denotes a root directory. + /// The extension of the specified path, including the period ., + /// or an empty string if no extension is present. /// - public static string? GetDirectoryName(string path) + public static string GetExtension(string path) { - if (string.IsNullOrEmpty(path)) - return null; + for (var i = path.Length - 1; i >= 0; i--) + { + if (path[i] == '.') + return path.AsSpan(i).ToString(); + + if (path[i] == '/') + break; + } + + return ""; + } + + /// + /// Returns the file name and extension for the specified path. + /// + /// The path from which to obtain the file name and extension. + /// + /// The file name and extension for the . + /// + public static string GetFileName(string path) + { + var p = path.AsSpan(); + var start = p.LastIndexOf('/'); + return start >= 0 + ? p.Slice(start + 1).ToString() + : ""; + } + + /// + /// Returns the directory portion for the specified path. + /// + /// The path to retrieve the directory portion from. + /// + /// Directory portion for , or an empty string if path denotes a root directory. + /// + public static string GetDirectoryName(string path) + { var index = path.AsSpan().LastIndexOf('/'); if (index < 0) return ""; var p = index; - while (p - 1 >= 0 && path[p - 1] == '/') + while (p - 1 >= 0 && (path[p - 1] == '/')) p--; return p switch { - 0 when index + 1 == path.Length => null, + 0 when index + 1 == path.Length => "", 0 => "/", _ => path[..p] }; diff --git a/Ramstack.FileProviders/ZipFileProvider.cs b/Ramstack.FileProviders/ZipFileProvider.cs index d4e0ea3..651503d 100644 --- a/Ramstack.FileProviders/ZipFileProvider.cs +++ b/Ramstack.FileProviders/ZipFileProvider.cs @@ -88,7 +88,7 @@ private static void Initialize(ZipArchive archive, Dictionary continue; var path = FilePath.Normalize(entry.FullName); - var directory = GetDirectory(FilePath.GetDirectoryName(path)!); + var directory = GetDirectory(FilePath.GetDirectoryName(path)); var file = new ZipFileInfo(entry); directory.RegisterFile(file); @@ -101,7 +101,7 @@ ZipDirectoryInfo GetDirectory(string path) return (ZipDirectoryInfo)di; di = new ZipDirectoryInfo(path); - var parent = GetDirectory(FilePath.GetDirectoryName(path)!); + var parent = GetDirectory(FilePath.GetDirectoryName(path)); parent.RegisterFile(di); cache.Add(path, di); From 94359e27aca6d57479797afd0b488df042c3126c Mon Sep 17 00:00:00 2001 From: rameel Date: Tue, 6 Aug 2024 13:44:42 +0500 Subject: [PATCH 2/8] Remove redundant parentheses --- Ramstack.FileProviders/Internal/FilePath.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Ramstack.FileProviders/Internal/FilePath.cs b/Ramstack.FileProviders/Internal/FilePath.cs index 7ca682a..1e00fec 100644 --- a/Ramstack.FileProviders/Internal/FilePath.cs +++ b/Ramstack.FileProviders/Internal/FilePath.cs @@ -68,7 +68,7 @@ public static string GetDirectoryName(string path) return ""; var p = index; - while (p - 1 >= 0 && (path[p - 1] == '/')) + while (p - 1 >= 0 && path[p - 1] == '/') p--; return p switch From fe9d1dc017cea8c0f75ec55c1fea55ad98b39c1f Mon Sep 17 00:00:00 2001 From: rameel Date: Tue, 6 Aug 2024 13:48:44 +0500 Subject: [PATCH 3/8] Remove unused FilePath.Combine method --- Ramstack.FileProviders/Internal/FilePath.cs | 27 --------------------- 1 file changed, 27 deletions(-) diff --git a/Ramstack.FileProviders/Internal/FilePath.cs b/Ramstack.FileProviders/Internal/FilePath.cs index 1e00fec..40af057 100644 --- a/Ramstack.FileProviders/Internal/FilePath.cs +++ b/Ramstack.FileProviders/Internal/FilePath.cs @@ -320,33 +320,6 @@ public static string Join(string path1, string path2) return string.Concat(path1, "/", path2); } - /// - /// Combines two strings into a path. - /// - /// The first path to combine. - /// The second path to combine. - /// - /// The combined paths. - /// If one of the specified paths is a zero-length string, this method returns the other path. - /// If contains an absolute path, this method returns . - /// - public static string Combine(string path1, string path2) - { - if (path2.Length == 0) - return path1; - - if (path1.Length == 0) - return path2; - - if (HasLeadingSlash(path2)) - return path2; - - if (HasTrailingSlash(path1)) - return path1 + path2; - - return path1 + "/" + path2; - } - /// /// Determines whether the specified path string starts with a directory separator. /// From 11735178e77cfff09db5cd67f877b55d5e039427 Mon Sep 17 00:00:00 2001 From: rameel Date: Tue, 6 Aug 2024 13:50:33 +0500 Subject: [PATCH 4/8] Remove redundant nullable warning suppression --- Ramstack.FileProviders/DirectoryNode.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Ramstack.FileProviders/DirectoryNode.cs b/Ramstack.FileProviders/DirectoryNode.cs index 965ca8a..cf9951b 100644 --- a/Ramstack.FileProviders/DirectoryNode.cs +++ b/Ramstack.FileProviders/DirectoryNode.cs @@ -44,7 +44,7 @@ public DirectoryNode? Parent if (IsRoot) return null; - var parent = FilePath.GetDirectoryName(FullName)!; + var parent = FilePath.GetDirectoryName(FullName); var directory = Provider.GetDirectoryContents(parent); return new DirectoryNode(Provider, parent, directory); } From f2db13d3d149346303626d9910288a07c92c16df Mon Sep 17 00:00:00 2001 From: rameel Date: Tue, 6 Aug 2024 13:52:30 +0500 Subject: [PATCH 5/8] Remove unused methods --- Ramstack.FileProviders/DirectoryNode.cs | 30 ------------------------- 1 file changed, 30 deletions(-) diff --git a/Ramstack.FileProviders/DirectoryNode.cs b/Ramstack.FileProviders/DirectoryNode.cs index cf9951b..3172d1e 100644 --- a/Ramstack.FileProviders/DirectoryNode.cs +++ b/Ramstack.FileProviders/DirectoryNode.cs @@ -77,36 +77,6 @@ internal DirectoryNode(IFileProvider provider, string path, IFileInfo file) : ba internal DirectoryNode(IFileProvider provider, string path, IDirectoryContents directory) : base(provider, path) => _directory = directory; - /// - /// Returns a directory with the specified path. - /// - /// The path that identifies the directory. - /// - /// The representing the desired directory. - /// - public DirectoryNode GetDirectory(string path) - { - path = FilePath.GetFullPath(FilePath.Combine(FullName, path)); - - var directory = Provider.GetDirectoryContents(path); - return new DirectoryNode(Provider, path, directory); - } - - /// - /// Returns a file with the specified path. - /// - /// The path that identifies the file. - /// - /// The representing the desired file. - /// - public FileNode GetFile(string path) - { - path = FilePath.GetFullPath(FilePath.Combine(FullName, path)); - - var file = Provider.GetFileInfo(path); - return new FileNode(Provider, path, file); - } - /// /// Returns an enumerable collection of files in the current directory. /// From 018ef81a0f871730413c656608fab43eda3c328d Mon Sep 17 00:00:00 2001 From: rameel Date: Tue, 6 Aug 2024 13:54:27 +0500 Subject: [PATCH 6/8] Update README --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 21103e0..b401bfc 100644 --- a/README.md +++ b/README.md @@ -16,8 +16,6 @@ Represents a lightweight .NET library of useful and convenient extensions for `Microsoft.Extensions.FileProviders` that enhances file handling capabilities in .NET applications. -[![.NET](https://github.com/rameel/ramstack.fileproviders/actions/workflows/test.yml/badge.svg)](https://github.com/rameel/ramstack.fileproviders/actions/workflows/test.yml) - ## Getting Started To install the `Ramstack.FileProviders` [NuGet package](https://www.nuget.org/packages/Ramstack.FileProviders) From 39aa148ff670cbba0c499f6622093261aa1dfad1 Mon Sep 17 00:00:00 2001 From: rameel Date: Tue, 6 Aug 2024 14:06:27 +0500 Subject: [PATCH 7/8] Update FilePath tests --- Ramstack.FileProviders.Tests/FilePathTests.cs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/Ramstack.FileProviders.Tests/FilePathTests.cs b/Ramstack.FileProviders.Tests/FilePathTests.cs index 6887be4..022e3e2 100644 --- a/Ramstack.FileProviders.Tests/FilePathTests.cs +++ b/Ramstack.FileProviders.Tests/FilePathTests.cs @@ -5,6 +5,23 @@ namespace Ramstack.FileProviders; [TestFixture] public class FilePathTests { + [TestCase("", ExpectedResult = "")] + [TestCase(".", ExpectedResult = ".")] + [TestCase("/", ExpectedResult = "")] + [TestCase("/.", ExpectedResult = ".")] + [TestCase("file.txt", ExpectedResult = ".txt")] + [TestCase("/path/to/file.txt", ExpectedResult = ".txt")] + [TestCase("/path/to/.hidden", ExpectedResult = ".hidden")] + [TestCase("/path/to/file", ExpectedResult = "")] + [TestCase("/path.with.dots/to/file.txt", ExpectedResult = ".txt")] + [TestCase("/path/with.dots/file.", ExpectedResult = ".")] + [TestCase("/path.with.dots/to/.hidden.ext", ExpectedResult = ".ext")] + [TestCase("file.with.multiple.dots.ext", ExpectedResult = ".ext")] + [TestCase("/path/to/file.with.multiple.dots.ext", ExpectedResult = ".ext")] + [TestCase("/.hidden", ExpectedResult = ".hidden")] + public string GetExtension(string path) => + FilePath.GetExtension(path); + [TestCase("/", ExpectedResult = true)] [TestCase("/a/b/c", ExpectedResult = true)] [TestCase("/a/./b/c", ExpectedResult = true)] From dbec8c7e0e45e9d69a31fb24fb3ad8c47a8ca17c Mon Sep 17 00:00:00 2001 From: rameel Date: Tue, 6 Aug 2024 14:15:13 +0500 Subject: [PATCH 8/8] Update FilePath tests --- Ramstack.FileProviders.Tests/FilePathTests.cs | 17 +++++++++++++++++ Ramstack.FileProviders/Internal/FilePath.cs | 2 +- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/Ramstack.FileProviders.Tests/FilePathTests.cs b/Ramstack.FileProviders.Tests/FilePathTests.cs index 022e3e2..f5a5cb1 100644 --- a/Ramstack.FileProviders.Tests/FilePathTests.cs +++ b/Ramstack.FileProviders.Tests/FilePathTests.cs @@ -22,6 +22,23 @@ public class FilePathTests public string GetExtension(string path) => FilePath.GetExtension(path); + [TestCase("", ExpectedResult = "")] + [TestCase(".", ExpectedResult = ".")] + [TestCase(".hidden", ExpectedResult = ".hidden")] + [TestCase("file.txt", ExpectedResult = "file.txt")] + [TestCase("/path/to/file.txt", ExpectedResult = "file.txt")] + [TestCase("/path/to/.hidden", ExpectedResult = ".hidden")] + [TestCase("/path/to/file", ExpectedResult = "file")] + [TestCase("/path/with.dots/file.txt", ExpectedResult = "file.txt")] + [TestCase("/path/with.dots/file.", ExpectedResult = "file.")] + [TestCase("/path/to/file.with.multiple.dots.ext", ExpectedResult = "file.with.multiple.dots.ext")] + [TestCase("/path/to/.hidden.ext", ExpectedResult = ".hidden.ext")] + [TestCase("/.hidden", ExpectedResult = ".hidden")] + [TestCase("/path/to/", ExpectedResult = "")] + [TestCase("/path/to/directory/", ExpectedResult = "")] + public string GetFileNameTest(string path) => + FilePath.GetFileName(path); + [TestCase("/", ExpectedResult = true)] [TestCase("/a/b/c", ExpectedResult = true)] [TestCase("/a/./b/c", ExpectedResult = true)] diff --git a/Ramstack.FileProviders/Internal/FilePath.cs b/Ramstack.FileProviders/Internal/FilePath.cs index 40af057..e4a5c8a 100644 --- a/Ramstack.FileProviders/Internal/FilePath.cs +++ b/Ramstack.FileProviders/Internal/FilePath.cs @@ -51,7 +51,7 @@ public static string GetFileName(string path) var start = p.LastIndexOf('/'); return start >= 0 ? p.Slice(start + 1).ToString() - : ""; + : path; } ///