diff --git a/.packageguard/cache.bin b/.packageguard/cache.bin
index 80d7d29..3b16981 100644
Binary files a/.packageguard/cache.bin and b/.packageguard/cache.bin differ
diff --git a/Build/_build.csproj b/Build/_build.csproj
index 43acdf6..3f03ec4 100644
--- a/Build/_build.csproj
+++ b/Build/_build.csproj
@@ -16,7 +16,7 @@
-
+
diff --git a/Pathy.ApiVerificationTests/ApprovedApi/pathy.globbing.net47.verified.txt b/Pathy.ApiVerificationTests/ApprovedApi/pathy.globbing.net47.verified.txt
index d1db159..e785eeb 100644
--- a/Pathy.ApiVerificationTests/ApprovedApi/pathy.globbing.net47.verified.txt
+++ b/Pathy.ApiVerificationTests/ApprovedApi/pathy.globbing.net47.verified.txt
@@ -1 +1,8 @@
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Pathy.Specs")]
+namespace Pathy
+{
+ public static class ChainablePathExtensions
+ {
+ public static Pathy.ChainablePath[] GlobFiles(this Pathy.ChainablePath path, string globPattern) { }
+ }
+}
\ No newline at end of file
diff --git a/Pathy.ApiVerificationTests/ApprovedApi/pathy.globbing.net8.0.verified.txt b/Pathy.ApiVerificationTests/ApprovedApi/pathy.globbing.net8.0.verified.txt
index d1db159..e785eeb 100644
--- a/Pathy.ApiVerificationTests/ApprovedApi/pathy.globbing.net8.0.verified.txt
+++ b/Pathy.ApiVerificationTests/ApprovedApi/pathy.globbing.net8.0.verified.txt
@@ -1 +1,8 @@
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Pathy.Specs")]
+namespace Pathy
+{
+ public static class ChainablePathExtensions
+ {
+ public static Pathy.ChainablePath[] GlobFiles(this Pathy.ChainablePath path, string globPattern) { }
+ }
+}
\ No newline at end of file
diff --git a/Pathy.ApiVerificationTests/ApprovedApi/pathy.globbing.netstandard2.0.verified.txt b/Pathy.ApiVerificationTests/ApprovedApi/pathy.globbing.netstandard2.0.verified.txt
index d1db159..e785eeb 100644
--- a/Pathy.ApiVerificationTests/ApprovedApi/pathy.globbing.netstandard2.0.verified.txt
+++ b/Pathy.ApiVerificationTests/ApprovedApi/pathy.globbing.netstandard2.0.verified.txt
@@ -1 +1,8 @@
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Pathy.Specs")]
+namespace Pathy
+{
+ public static class ChainablePathExtensions
+ {
+ public static Pathy.ChainablePath[] GlobFiles(this Pathy.ChainablePath path, string globPattern) { }
+ }
+}
\ No newline at end of file
diff --git a/Pathy.ApiVerificationTests/ApprovedApi/pathy.globbing.netstandard2.1.verified.txt b/Pathy.ApiVerificationTests/ApprovedApi/pathy.globbing.netstandard2.1.verified.txt
index d1db159..e785eeb 100644
--- a/Pathy.ApiVerificationTests/ApprovedApi/pathy.globbing.netstandard2.1.verified.txt
+++ b/Pathy.ApiVerificationTests/ApprovedApi/pathy.globbing.netstandard2.1.verified.txt
@@ -1 +1,8 @@
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Pathy.Specs")]
+namespace Pathy
+{
+ public static class ChainablePathExtensions
+ {
+ public static Pathy.ChainablePath[] GlobFiles(this Pathy.ChainablePath path, string globPattern) { }
+ }
+}
\ No newline at end of file
diff --git a/Pathy.ApiVerificationTests/Pathy.ApiVerificationTests.csproj b/Pathy.ApiVerificationTests/Pathy.ApiVerificationTests.csproj
index 0a5a52d..2a08a4f 100644
--- a/Pathy.ApiVerificationTests/Pathy.ApiVerificationTests.csproj
+++ b/Pathy.ApiVerificationTests/Pathy.ApiVerificationTests.csproj
@@ -13,7 +13,7 @@
-
+
diff --git a/Pathy.Globbing/Pathy.Globbing.csproj b/Pathy.Globbing/Pathy.Globbing.csproj
index e92e6d7..7486775 100644
--- a/Pathy.Globbing/Pathy.Globbing.csproj
+++ b/Pathy.Globbing/Pathy.Globbing.csproj
@@ -7,7 +7,7 @@
disable
.nuspec
version=$(Version)
- MYPACKAGE_COMPILE
+ PATHY_PUBLIC
1591;1573
False
$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb
diff --git a/Pathy.Globbing/PathyGlobbing.cs b/Pathy.Globbing/PathyGlobbing.cs
index 2ef14e0..74a13f5 100644
--- a/Pathy.Globbing/PathyGlobbing.cs
+++ b/Pathy.Globbing/PathyGlobbing.cs
@@ -1,6 +1,7 @@
//
using System;
+using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Microsoft.Extensions.FileSystemGlobbing;
using Microsoft.Extensions.FileSystemGlobbing.Abstractions;
@@ -10,32 +11,48 @@
#nullable disable
// ReSharper disable once CheckNamespace
-namespace Pathy;
-
+namespace Pathy
+{
#if PATHY_PUBLIC
-public static class ChainablePathExtensions
+ public static class ChainablePathExtensions
#else
-internal static class ChainablePathExtensions
+ [global::Microsoft.CodeAnalysis.Embedded]
+ internal static class ChainablePathExtensions
#endif
+ {
+ ///
+ /// Matches files in the specified directory or subdirectories according to the provided glob pattern
+ /// and returns them as an array of objects.
+ ///
+ ///
+ /// See also
+ ///
+ /// The base directory path to start the glob search from.
+ /// The glob pattern used to match file paths, e.g. **/*.md or dir/**/*
+ public static ChainablePath[] GlobFiles(this ChainablePath path, string globPattern)
+ {
+ Matcher matcher = new(StringComparison.OrdinalIgnoreCase);
+ matcher.AddInclude(globPattern);
+
+ return matcher
+ .Execute(new DirectoryInfoWrapper(path.ToDirectoryInfo()))
+ .Files
+ .Select(file => ChainablePath.From(path / file.Path))
+ .ToArray();
+ }
+ }
+}
+
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+namespace Microsoft.CodeAnalysis
{
///
- /// Matches files in the specified directory or subdirectories according to the provided glob pattern
- /// and returns them as an array of objects.
+ /// A special attribute recognized by Roslyn, that marks a type as "embedded", meaning it won't ever be visible from other assemblies.
///
- ///
- /// See also
- ///
- /// The base directory path to start the glob search from.
- /// The glob pattern used to match file paths, e.g. **/*.md or dir/**/*
- public static ChainablePath[] GlobFiles(this ChainablePath path, string globPattern)
+ [AttributeUsage(AttributeTargets.All)]
+ [ExcludeFromCodeCoverage]
+ internal sealed class EmbeddedAttribute : Attribute
{
- Matcher matcher = new(StringComparison.OrdinalIgnoreCase);
- matcher.AddInclude(globPattern);
-
- return matcher
- .Execute(new DirectoryInfoWrapper(path.ToDirectoryInfo()))
- .Files
- .Select(file => ChainablePath.From(path / file.Path))
- .ToArray();
}
}
diff --git a/Pathy.Specs/ChainablePathSpecs.cs b/Pathy.Specs/ChainablePathSpecs.cs
index e92c703..94fa5f3 100644
--- a/Pathy.Specs/ChainablePathSpecs.cs
+++ b/Pathy.Specs/ChainablePathSpecs.cs
@@ -1,6 +1,5 @@
using System;
using System.IO;
-using System.Linq;
using System.Reflection;
using FluentAssertions;
using Xunit;
diff --git a/Pathy.Specs/Pathy.Specs.csproj b/Pathy.Specs/Pathy.Specs.csproj
index a9b22a8..e837617 100644
--- a/Pathy.Specs/Pathy.Specs.csproj
+++ b/Pathy.Specs/Pathy.Specs.csproj
@@ -18,7 +18,7 @@
-
+
runtime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/Pathy/ChainablePath.cs b/Pathy/ChainablePath.cs
index 90d9ecc..430cc1d 100644
--- a/Pathy/ChainablePath.cs
+++ b/Pathy/ChainablePath.cs
@@ -1,6 +1,7 @@
//
using System;
+using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
@@ -8,347 +9,348 @@
#pragma warning disable
-namespace Pathy;
-
-///
-/// Represents an absolute or relative path to a directory or file that simplifies operations like combining paths using
-/// the / operator
-///
+namespace Pathy
+{
+ ///
+ /// Represents an absolute or relative path to a directory or file that simplifies operations like combining paths using
+ /// the / operator
+ ///
#if PATHY_PUBLIC
-public readonly record struct ChainablePath
+ public readonly record struct ChainablePath
#else
-internal readonly record struct ChainablePath
+ [global::Microsoft.CodeAnalysis.Embedded]
+ internal readonly record struct ChainablePath
#endif
-{
- private readonly string path = string.Empty;
-
- private ChainablePath(string path)
{
- this.path = path;
- }
+ private readonly string path = string.Empty;
- ///
- /// Represents an empty instance.
- ///
- public static ChainablePath Empty { get; } = new(string.Empty);
+ private ChainablePath(string path)
+ {
+ this.path = path;
+ }
- ///
- /// Represents a not pointing to any file or directory.
- ///
- ///
- /// Implements the Null Pattern and should be used as a replacement of
- ///
- public static ChainablePath Null { get; } = new(string.Empty);
+ ///
+ /// Represents an empty instance.
+ ///
+ public static ChainablePath Empty { get; } = new(string.Empty);
+
+ ///
+ /// Represents a not pointing to any file or directory.
+ ///
+ ///
+ /// Implements the Null Pattern and should be used as a replacement of
+ ///
+ public static ChainablePath Null { get; } = new(string.Empty);
+
+ ///
+ /// Gets a default, empty instance.
+ ///
+ public static ChainablePath New => new(string.Empty);
+
+ ///
+ /// Creates a new instance of representing the specified path.
+ ///
+ ///
+ /// The string representation of the path. This can be relative or absolute.
+ ///
+ ///
+ /// A object representing the normalized path.
+ ///
+ ///
+ /// Thrown if the is null, empty, or invalid.
+ ///
+ public static ChainablePath From(string path)
+ {
+ if (path is null or { Length: 0 })
+ {
+ throw new ArgumentException("Path cannot be null or empty", nameof(path));
+ }
- ///
- /// Gets a default, empty instance.
- ///
- public static ChainablePath New => new(string.Empty);
+ try
+ {
+ path = NormalizeSlashes(path);
- ///
- /// Creates a new instance of representing the specified path.
- ///
- ///
- /// The string representation of the path. This can be relative or absolute.
- ///
- ///
- /// A object representing the normalized path.
- ///
- ///
- /// Thrown if the is null, empty, or invalid.
- ///
- public static ChainablePath From(string path)
- {
- if (path is null or { Length: 0 })
+ if (path[path.Length - 1] == Path.VolumeSeparatorChar)
+ {
+ path += Path.DirectorySeparatorChar;
+ }
+
+ if (Path.IsPathRooted(path))
+ {
+ return new ChainablePath(Path.GetFullPath(path));
+ }
+
+ return new ChainablePath(path);
+ }
+ catch (NotSupportedException)
+ {
+ throw new ArgumentException($"Path {path} is not valid", nameof(path));
+ }
+ }
+
+ ///
+ /// Creates a new instance of representing the first existing path from the specified list of paths.
+ ///
+ ///
+ /// An array of string representations of paths to check for existence. Paths are checked in the order provided.
+ ///
+ ///
+ /// A object representing the first path that exists or if none exist.
+ ///
+ ///
+ /// Thrown if the array is null.
+ ///
+ ///
+ /// Thrown if the array is empty.
+ ///
+ public static ChainablePath FindFirst(params string[] paths)
{
- throw new ArgumentException("Path cannot be null or empty", nameof(path));
+ if (paths == null)
+ {
+ throw new ArgumentNullException(nameof(paths));
+ }
+
+ return FindFirst(paths.Select(From).ToArray());
}
- try
+ ///
+ /// Creates a new instance of representing the first existing path from the specified list of paths.
+ ///
+ ///
+ /// An array of instances to check for existence. Paths are checked in the order provided.
+ ///
+ ///
+ /// A object representing the first path that exists or if none exist.
+ ///
+ ///
+ /// Thrown if the array is null.
+ ///
+ ///
+ /// Thrown if the array is empty.
+ ///
+ public static ChainablePath FindFirst(params ChainablePath[] paths)
{
- path = NormalizeSlashes(path);
+ if (paths == null)
+ {
+ throw new ArgumentNullException(nameof(paths));
+ }
- if (path[path.Length - 1] == Path.VolumeSeparatorChar)
+ if (paths.Length == 0)
{
- path += Path.DirectorySeparatorChar;
+ throw new ArgumentException("At least one path must be provided", nameof(paths));
}
- if (Path.IsPathRooted(path))
+ foreach (var path in paths)
{
- return new ChainablePath(Path.GetFullPath(path));
+ if (path.Exists)
+ {
+ return path;
+ }
}
- return new ChainablePath(path);
+ return Empty;
}
- catch (NotSupportedException)
+
+ private static string NormalizeSlashes(string path)
{
- throw new ArgumentException($"Path {path} is not valid", nameof(path));
+ return path.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
}
- }
- ///
- /// Creates a new instance of representing the first existing path from the specified list of paths.
- ///
- ///
- /// An array of string representations of paths to check for existence. Paths are checked in the order provided.
- ///
- ///
- /// A object representing the first path that exists or if none exist.
- ///
- ///
- /// Thrown if the array is null.
- ///
- ///
- /// Thrown if the array is empty.
- ///
- public static ChainablePath FindFirst(params string[] paths)
- {
- if (paths == null)
+ ///
+ /// Combines a instance with a string representing a sub-path while
+ /// handling the path separators suitable for the specific operating system.
+ ///
+ ///
+ ///
+ /// var combinedPath = ChainablePath.From("C:/BasePath") / "SubPath" / "File.txt";
+ ///
+ ///
+ ///
+ /// You don't need to add any slashes before the sub-path. The operator will handle it for you.
+ ///
+ ///
+ /// The base to which the will be appended.
+ ///
+ ///
+ /// The string representation of the relative or additional path to combine with .
+ ///
+ ///
+ /// A new instance representing the combined path.
+ ///
+ ///
+ /// Thrown if either or is null.
+ ///
+ public static ChainablePath operator /(ChainablePath leftPath, string subPath)
{
- throw new ArgumentNullException(nameof(paths));
+ return From(Path.Combine(leftPath.path, subPath));
}
- return FindFirst(paths.Select(From).ToArray());
- }
-
- ///
- /// Creates a new instance of representing the first existing path from the specified list of paths.
- ///
- ///
- /// An array of instances to check for existence. Paths are checked in the order provided.
- ///
- ///
- /// A object representing the first path that exists or if none exist.
- ///
- ///
- /// Thrown if the array is null.
- ///
- ///
- /// Thrown if the array is empty.
- ///
- public static ChainablePath FindFirst(params ChainablePath[] paths)
- {
- if (paths == null)
+ ///
+ /// Combines a instance with a string representing a sub-path while
+ /// handling the path separators suitable for the specific operating system.
+ ///
+ ///
+ ///
+ /// var combinedPath = ChainablePath.From("C:/BasePath") / "SubPath" / "File.txt";
+ ///
+ ///
+ ///
+ /// You don't need to add any slashes before the sub-path. The operator will handle it for you.
+ ///
+ ///
+ /// The base to which the will be appended.
+ ///
+ ///
+ /// The string representation of the relative or additional path to combine with .
+ ///
+ ///
+ /// A new instance representing the combined path.
+ ///
+ ///
+ /// Thrown if either or is null.
+ ///
+ public static ChainablePath operator /(ChainablePath? leftPath, string subPath)
{
- throw new ArgumentNullException(nameof(paths));
+ return From(Path.Combine(leftPath.GetValueOrDefault(New), subPath));
}
- if (paths.Length == 0)
+ ///
+ /// Adds a raw string to the end of a instance.
+ ///
+ ///
+ /// The base object representing an initial path.
+ ///
+ ///
+ /// The additional string representing a relative path or file extension (with dot) to append to the .
+ ///
+ ///
+ /// A new instance representing the combined path of and .
+ ///
+ public static ChainablePath operator +(ChainablePath leftPath, string additionalPath)
{
- throw new ArgumentException("At least one path must be provided", nameof(paths));
+ return From(leftPath.ToString() + additionalPath);
}
- foreach (var path in paths)
+ ///
+ /// Gets a value indicating whether the current instance is equal to .
+ ///
+ public bool IsNull => Equals(Null);
+
+ ///
+ /// Gets the name of the file or directory represented by the current path, without the parent directory.
+ ///
+ public string Name => Path.GetFileName(path);
+
+ ///
+ /// If the current path represents a file, gets the directory of that file.
+ /// Or, if the current path represents a directory, gets the parent directory.
+ /// Returns if the path represents the root of a file system.
+ ///
+ public ChainablePath Directory
{
- if (path.Exists)
+ get
{
- return path;
+ string directory = DirectoryName;
+ if (directory.Length > 0)
+ {
+ return From(directory);
+ }
+
+ return Empty;
}
}
- return Empty;
- }
-
- private static string NormalizeSlashes(string path)
- {
- return path.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
- }
-
- ///
- /// Combines a instance with a string representing a sub-path while
- /// handling the path separators suitable for the specific operating system.
- ///
- ///
- ///
- /// var combinedPath = ChainablePath.From("C:/BasePath") / "SubPath" / "File.txt";
- ///
- ///
- ///
- /// You don't need to add any slashes before the sub-path. The operator will handle it for you.
- ///
- ///
- /// The base to which the will be appended.
- ///
- ///
- /// The string representation of the relative or additional path to combine with .
- ///
- ///
- /// A new instance representing the combined path.
- ///
- ///
- /// Thrown if either or is null.
- ///
- public static ChainablePath operator /(ChainablePath leftPath, string subPath)
- {
- return From(Path.Combine(leftPath.path, subPath));
- }
-
- ///
- /// Combines a instance with a string representing a sub-path while
- /// handling the path separators suitable for the specific operating system.
- ///
- ///
- ///
- /// var combinedPath = ChainablePath.From("C:/BasePath") / "SubPath" / "File.txt";
- ///
- ///
- ///
- /// You don't need to add any slashes before the sub-path. The operator will handle it for you.
- ///
- ///
- /// The base to which the will be appended.
- ///
- ///
- /// The string representation of the relative or additional path to combine with .
- ///
- ///
- /// A new instance representing the combined path.
- ///
- ///
- /// Thrown if either or is null.
- ///
- public static ChainablePath operator /(ChainablePath? leftPath, string subPath)
- {
- return From(Path.Combine(leftPath.GetValueOrDefault(New), subPath));
- }
-
- ///
- /// Adds a raw string to the end of a instance.
- ///
- ///
- /// The base object representing an initial path.
- ///
- ///
- /// The additional string representing a relative path or file extension (with dot) to append to the .
- ///
- ///
- /// A new instance representing the combined path of and .
- ///
- public static ChainablePath operator +(ChainablePath leftPath, string additionalPath)
- {
- return From(leftPath.ToString() + additionalPath);
- }
-
- ///
- /// Gets a value indicating whether the current instance is equal to .
- ///
- public bool IsNull => Equals(Null);
-
- ///
- /// Gets the name of the file or directory represented by the current path, without the parent directory.
- ///
- public string Name => Path.GetFileName(path);
-
- ///
- /// If the current path represents a file, gets the directory of that file.
- /// Or, if the current path represents a directory, gets the parent directory.
- /// Returns if the path represents the root of a file system.
- ///
- public ChainablePath Directory
- {
- get
+ ///
+ /// If the current path represents a file, gets the directory of that file.
+ /// Or, if the current path represents a directory, gets the parent directory.
+ /// Returns if the path represents the root of a file system.
+ ///
+ public ChainablePath Parent => From(DirectoryName);
+
+ ///
+ /// If the current path represents a file, gets the directory of that file.
+ /// Or, if the current path represents a directory, gets the parent directory.
+ /// Returns an empty string if the path represents the root of a file system.
+ ///
+ public string DirectoryName
{
- string directory = DirectoryName;
- if (directory.Length > 0)
+ get
{
- return From(directory);
+ return Path.GetDirectoryName(path.TrimEnd(Path.DirectorySeparatorChar)) ?? "";
}
-
- return Empty;
}
- }
-
- ///
- /// If the current path represents a file, gets the directory of that file.
- /// Or, if the current path represents a directory, gets the parent directory.
- /// Returns if the path represents the root of a file system.
- ///
- public ChainablePath Parent => From(DirectoryName);
-
- ///
- /// If the current path represents a file, gets the directory of that file.
- /// Or, if the current path represents a directory, gets the parent directory.
- /// Returns an empty string if the path represents the root of a file system.
- ///
- public string DirectoryName
- {
- get
- {
- return Path.GetDirectoryName(path.TrimEnd(Path.DirectorySeparatorChar)) ?? "";
- }
- }
-
- ///
- /// Indicates whether the current path is rooted, meaning it begins with a root component such as
- /// a drive letter (e.g., "C:\") or directory separator (e.g., "/").
- /// Returns true if the path is rooted; otherwise, false.
- ///
- public bool IsRooted => Path.IsPathRooted(path);
-
- ///
- /// Returns true if the path represents an existing file or directory; otherwise, returns false.
- ///
- public bool Exists => FileExists || DirectoryExists;
-
- ///
- /// Returns true if a file exists at the path; otherwise, false.
- ///
- public bool FileExists => File.Exists(path);
-
- ///
- /// Returns true if the path exists and is a directory; otherwise, false.
- ///
- public bool DirectoryExists => System.IO.Directory.Exists(path);
- ///
- /// Gets the file extension of the current path, including the leading period (".") if an extension is present.
- /// Returns an empty string if the path does not contain a file extension.
- ///
- public string Extension
- {
- get
+ ///
+ /// Indicates whether the current path is rooted, meaning it begins with a root component such as
+ /// a drive letter (e.g., "C:\") or directory separator (e.g., "/").
+ /// Returns true if the path is rooted; otherwise, false.
+ ///
+ public bool IsRooted => Path.IsPathRooted(path);
+
+ ///
+ /// Returns true if the path represents an existing file or directory; otherwise, returns false.
+ ///
+ public bool Exists => FileExists || DirectoryExists;
+
+ ///
+ /// Returns true if a file exists at the path; otherwise, false.
+ ///
+ public bool FileExists => File.Exists(path);
+
+ ///
+ /// Returns true if the path exists and is a directory; otherwise, false.
+ ///
+ public bool DirectoryExists => System.IO.Directory.Exists(path);
+
+ ///
+ /// Gets the file extension of the current path, including the leading period (".") if an extension is present.
+ /// Returns an empty string if the path does not contain a file extension.
+ ///
+ public string Extension
{
- return Path.GetExtension(path);
+ get
+ {
+ return Path.GetExtension(path);
+ }
}
- }
- ///
- /// Gets the root directory of the current path.
- ///
- public ChainablePath Root => From(Path.GetPathRoot(path));
-
- ///
- /// Gets a value indicating whether the path represented by the current object points to an existing file.
- ///
- public bool IsFile => File.Exists(ToString());
-
- ///
- /// Gets a value indicating whether the current path represents an existing directory.
- ///
- public bool IsDirectory => System.IO.Directory.Exists(ToString());
-
- ///
- /// Gets a instance representing the current working directory of the application.
- ///
- public static ChainablePath Current => From(Environment.CurrentDirectory);
-
- ///
- /// Gets a instance representing the system's temporary directory.
- ///
- public static ChainablePath Temp => From(Path.GetTempPath());
-
- ///
- /// Returns a new instance representing the path relative to the specified base path.
- ///
- ///
- /// The base path to which the current path should be relativized. It must be an absolute path.
- ///
- ///
- /// A instance representing the relative path from the base path to this path.
- ///
- ///
- /// Thrown if is not absolute, or if this path is not absolute.
- ///
+ ///
+ /// Gets the root directory of the current path.
+ ///
+ public ChainablePath Root => From(Path.GetPathRoot(path));
+
+ ///
+ /// Gets a value indicating whether the path represented by the current object points to an existing file.
+ ///
+ public bool IsFile => File.Exists(ToString());
+
+ ///
+ /// Gets a value indicating whether the current path represents an existing directory.
+ ///
+ public bool IsDirectory => System.IO.Directory.Exists(ToString());
+
+ ///
+ /// Gets a instance representing the current working directory of the application.
+ ///
+ public static ChainablePath Current => From(Environment.CurrentDirectory);
+
+ ///
+ /// Gets a instance representing the system's temporary directory.
+ ///
+ public static ChainablePath Temp => From(Path.GetTempPath());
+
+ ///
+ /// Returns a new instance representing the path relative to the specified base path.
+ ///
+ ///
+ /// The base path to which the current path should be relativized. It must be an absolute path.
+ ///
+ ///
+ /// A instance representing the relative path from the base path to this path.
+ ///
+ ///
+ /// Thrown if is not absolute, or if this path is not absolute.
+ ///
#if NET6_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER
public ChainablePath AsRelativeTo(ChainablePath basePath)
{
@@ -356,159 +358,175 @@ public ChainablePath AsRelativeTo(ChainablePath basePath)
}
#endif
- ///
- /// Returns the string representation of the current instance.
- ///
- public override string ToString()
- {
- return path;
- }
-
- ///
- /// Allows casting a instance to a string so it can be used anywhere where a path as string is expected.
- ///
- public static implicit operator string(ChainablePath chainablePath)
- {
- return chainablePath.ToString();
- }
-
- ///
- /// Allows casting a string to a instance.
- ///
- ///
- /// Serves as a shortcut for .
- ///
- public static implicit operator ChainablePath(string path)
- {
- return From(path);
- }
+ ///
+ /// Returns the string representation of the current instance.
+ ///
+ public override string ToString()
+ {
+ return path;
+ }
- ///
- /// Converts the current instance to a object.
- ///
- public DirectoryInfo ToDirectoryInfo()
- {
- return new DirectoryInfo(ToString());
- }
+ ///
+ /// Allows casting a instance to a string so it can be used anywhere where a path as string is expected.
+ ///
+ public static implicit operator string(ChainablePath chainablePath)
+ {
+ return chainablePath.ToString();
+ }
- ///
- /// Converts the current instance to a object.
- ///
- public FileInfo ToFileInfo()
- {
- return new FileInfo(ToString());
- }
+ ///
+ /// Allows casting a string to a instance.
+ ///
+ ///
+ /// Serves as a shortcut for .
+ ///
+ public static implicit operator ChainablePath(string path)
+ {
+ return From(path);
+ }
- ///
- /// Determines if the current path has the specified file extension.
- ///
- ///
- /// The file extension to check for, with or without the leading period (e.g., ".txt").
- ///
- public bool HasExtension(string extension)
- {
- if (string.IsNullOrEmpty(extension))
+ ///
+ /// Converts the current instance to a object.
+ ///
+ public DirectoryInfo ToDirectoryInfo()
{
- throw new ArgumentException("Extension cannot be null or empty", nameof(extension));
+ return new DirectoryInfo(ToString());
}
- // Ensure the extension starts with a dot
- if (!extension.StartsWith(".", StringComparison.InvariantCulture))
+ ///
+ /// Converts the current instance to a object.
+ ///
+ public FileInfo ToFileInfo()
{
- extension = '.' + extension;
+ return new FileInfo(ToString());
}
- return string.Equals(Extension, extension, StringComparison.OrdinalIgnoreCase);
- }
+ ///
+ /// Determines if the current path has the specified file extension.
+ ///
+ ///
+ /// The file extension to check for, with or without the leading period (e.g., ".txt").
+ ///
+ public bool HasExtension(string extension)
+ {
+ if (string.IsNullOrEmpty(extension))
+ {
+ throw new ArgumentException("Extension cannot be null or empty", nameof(extension));
+ }
- ///
- /// Converts the current to an absolute path using the current working directory.
- ///
- public ChainablePath ToAbsolute()
- {
- return Path.GetFullPath(this);
- }
+ // Ensure the extension starts with a dot
+ if (!extension.StartsWith(".", StringComparison.InvariantCulture))
+ {
+ extension = '.' + extension;
+ }
- ///
- /// Converts the current instance to an absolute path, using the specified parent
- /// path as the base.
- ///
- public object ToAbsolute(ChainablePath parentPath)
- {
- if (!parentPath.IsRooted)
- {
- throw new ArgumentException("Parent path must be an absolute path", nameof(parentPath));
+ return string.Equals(Extension, extension, StringComparison.OrdinalIgnoreCase);
}
- return From(Path.Combine(parentPath.ToString(), this.ToString()));
- }
-
- ///
- /// Finds the first parent directory in the hierarchy that contains a file matching any of the provided wildcard patterns.
- ///
- /// One or more wildcard patterns to match against files in parent directories (e.g., "*.sln", "*.slnx").
- ///
- /// A representing the first parent directory that contains a matching file,
- /// or if no parent directory contains a matching file.
- ///
- /// Thrown if no wildcards are provided or if any wildcard is null or empty.
- public ChainablePath FindParentWithFileMatching(params string[] wildcards)
- {
- if (wildcards == null || wildcards.Length == 0)
+ ///
+ /// Converts the current to an absolute path using the current working directory.
+ ///
+ public ChainablePath ToAbsolute()
{
- throw new ArgumentException("At least one wildcard pattern must be provided", nameof(wildcards));
+ return Path.GetFullPath(this);
}
- foreach (string wildcard in wildcards)
+ ///
+ /// Converts the current instance to an absolute path, using the specified parent
+ /// path as the base.
+ ///
+ public object ToAbsolute(ChainablePath parentPath)
{
- if (string.IsNullOrWhiteSpace(wildcard))
+ if (!parentPath.IsRooted)
{
- throw new ArgumentException("Wildcard patterns cannot be null or empty", nameof(wildcards));
+ throw new ArgumentException("Parent path must be an absolute path", nameof(parentPath));
}
- }
- // Start from the directory containing this path, or the path itself if it's already a directory
- ChainablePath currentDirectory = IsFile ? Directory : this;
+ return From(Path.Combine(parentPath.ToString(), ToString()));
+ }
- while (currentDirectory != Root && currentDirectory != Empty && currentDirectory.DirectoryExists)
+ ///
+ /// Finds the first parent directory in the hierarchy that contains a file matching any of the provided wildcard patterns.
+ ///
+ /// One or more wildcard patterns to match against files in parent directories (e.g., "*.sln", "*.slnx").
+ ///
+ /// A representing the first parent directory that contains a matching file,
+ /// or if no parent directory contains a matching file.
+ ///
+ /// Thrown if no wildcards are provided or if any wildcard is null or empty.
+ public ChainablePath FindParentWithFileMatching(params string[] wildcards)
{
+ if (wildcards == null || wildcards.Length == 0)
+ {
+ throw new ArgumentException("At least one wildcard pattern must be provided", nameof(wildcards));
+ }
+
foreach (string wildcard in wildcards)
{
- // Check if any files in the current directory match the wildcards
- if (System.IO.Directory.GetFiles(currentDirectory, wildcard).Any())
+ if (string.IsNullOrWhiteSpace(wildcard))
{
- return currentDirectory;
+ throw new ArgumentException("Wildcard patterns cannot be null or empty", nameof(wildcards));
}
}
- // Move to the parent directory
- currentDirectory = currentDirectory.Parent;
- }
+ // Start from the directory containing this path, or the path itself if it's already a directory
+ ChainablePath currentDirectory = IsFile ? Directory : this;
- return Empty;
+ while (currentDirectory != Root && currentDirectory != Empty && currentDirectory.DirectoryExists)
+ {
+ foreach (string wildcard in wildcards)
+ {
+ // Check if any files in the current directory match the wildcards
+ if (System.IO.Directory.GetFiles(currentDirectory, wildcard).Any())
+ {
+ return currentDirectory;
+ }
+ }
+
+ // Move to the parent directory
+ currentDirectory = currentDirectory.Parent;
+ }
+
+ return Empty;
+ }
}
-}
#if PATHY_PUBLIC
-public static class StringExtensions
+ public static class StringExtensions
#else
-internal static class StringExtensions
+ [global::Microsoft.CodeAnalysis.Embedded]
+ internal static class StringExtensions
#endif
+ {
+ ///
+ /// Converts the specified string representation of a path to a instance.
+ ///
+ ///
+ /// The string representation of the path to convert.
+ ///
+ ///
+ /// A instance representing the specified path.
+ ///
+ ///
+ /// Thrown if the is null, empty, or invalid.
+ ///
+ public static ChainablePath ToPath(this string path)
+ {
+ return ChainablePath.From(path);
+ }
+ }
+}
+
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+namespace Microsoft.CodeAnalysis
{
///
- /// Converts the specified string representation of a path to a instance.
+ /// A special attribute recognized by Roslyn, that marks a type as "embedded", meaning it won't ever be visible from other assemblies.
///
- ///
- /// The string representation of the path to convert.
- ///
- ///
- /// A instance representing the specified path.
- ///
- ///
- /// Thrown if the is null, empty, or invalid.
- ///
- public static ChainablePath ToPath(this string path)
+ [AttributeUsage(AttributeTargets.All)]
+ [ExcludeFromCodeCoverage]
+ internal sealed class EmbeddedAttribute : Attribute
{
- return ChainablePath.From(path);
}
}