Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
# Set default behaviour to automatically normalize line endings.
* text=auto

# csharp files to match .editorconfig
*.cs text eol=crlf

# Force batch scripts to always use CRLF line endings so that if a repo is accessed
# in Windows via a file share from Linux, the scripts will work.
*.{cmd,[cC][mM][dD]} text eol=crlf
Expand Down
2,104 changes: 35 additions & 2,069 deletions Semantics.Paths/CompatibilitySuppressions.xml

Large diffs are not rendered by default.

9 changes: 9 additions & 0 deletions Semantics.Paths/Interfaces/IDirectoryName.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,13 @@ namespace ktsu.Semantics.Paths;
/// </summary>
public interface IDirectoryName
{
/// <summary>
/// Gets the underlying string value for interoperability with non-semantic string operations.
/// </summary>
/// <value>The raw string value of this directory name.</value>
/// <remarks>
/// Exposed on the interface so that code holding an <see cref="IDirectoryName"/> — for example the results of
/// a polymorphic directory name API — can read the value without downcasting to a concrete type.
/// </remarks>
public string WeakString { get; }
}
9 changes: 9 additions & 0 deletions Semantics.Paths/Interfaces/IFileExtension.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,13 @@ namespace ktsu.Semantics.Paths;
/// </summary>
public interface IFileExtension
{
/// <summary>
/// Gets the underlying string value for interoperability with non-semantic string operations.
/// </summary>
/// <value>The raw string value of this file extension.</value>
/// <remarks>
/// Exposed on the interface so that code holding an <see cref="IFileExtension"/> — for example the results of
/// a polymorphic extension API — can read the value without downcasting to a concrete type.
/// </remarks>
public string WeakString { get; }
}
9 changes: 9 additions & 0 deletions Semantics.Paths/Interfaces/IFileName.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,13 @@ namespace ktsu.Semantics.Paths;
/// </summary>
public interface IFileName
{
/// <summary>
/// Gets the underlying string value for interoperability with non-semantic string operations.
/// </summary>
/// <value>The raw string value of this filename.</value>
/// <remarks>
/// Exposed on the interface so that code holding an <see cref="IFileName"/> — for example the results of
/// a polymorphic filename API — can read the value without downcasting to a concrete type.
/// </remarks>
public string WeakString { get; }
}
13 changes: 12 additions & 1 deletion Semantics.Paths/Interfaces/IPath.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,20 @@

namespace ktsu.Semantics.Paths;

using System;

/// <summary>
/// Base interface for all path types
/// </summary>
public interface IPath
public interface IPath : IComparable<IPath>
{
/// <summary>
/// Gets the underlying string value for interoperability with non-semantic string operations.
/// </summary>
/// <value>The raw string value of this path.</value>
/// <remarks>
/// Exposed on the interface so that code holding an <see cref="IPath"/> — for example the results of
/// <see cref="SemanticDirectoryPath{TDerived}.GetContents"/> — can read the value without downcasting to a concrete type.
/// </remarks>
public string WeakString { get; }
}
23 changes: 22 additions & 1 deletion Semantics.Paths/SemanticPath.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ namespace ktsu.Semantics.Paths;
/// they contain valid path characters and reasonable lengths.
/// </remarks>
[IsPath]
public abstract record SemanticPath<TDerived> : SemanticString<TDerived>
public abstract record SemanticPath<TDerived> : SemanticString<TDerived>, IComparable<IPath>
where TDerived : SemanticPath<TDerived>
{

Expand Down Expand Up @@ -66,6 +66,27 @@ public abstract record SemanticPath<TDerived> : SemanticString<TDerived>
/// </remarks>
public bool IsFile => File.Exists(WeakString);

/// <summary>
/// Compares this path with another path by their underlying string values.
/// </summary>
/// <param name="other">The path to compare with, or <see langword="null"/>.</param>
/// <returns>
/// A 32-bit signed integer that indicates whether this path precedes, follows, or appears in the
/// same position in the sort order as <paramref name="other"/>. A <see langword="null"/>
/// <paramref name="other"/> sorts before this path.
/// </returns>
/// <remarks>
/// Implemented explicitly so that it does not join the overload set of the inherited
/// <see cref="SemanticString{TDerived}.CompareTo(ISemanticString)"/>. A public overload taking
/// <see cref="IPath"/> would make <c>pathA.CompareTo(pathB)</c> ambiguous for callers, because a
/// concrete path satisfies both parameter types and neither is more specific. Declaring
/// <see cref="IComparable{T}"/> of <see cref="IPath"/> is what lets
/// <see cref="Comparer{T}.Default"/> sort an <see cref="IPath"/> collection through the generic
/// comparison path instead of boxing into the non-generic
/// <see cref="IComparable.CompareTo(object)"/>.
/// </remarks>
int IComparable<IPath>.CompareTo(IPath? other) => WeakString.CompareTo(strB: other?.WeakString);

/// <summary>
/// Normalizes the path by standardizing directory separators and removing trailing separators.
/// </summary>
Expand Down
10 changes: 5 additions & 5 deletions Semantics.Paths/Semantics.Paths.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
<PropertyGroup>
<TargetFrameworks>net10.0;net9.0;net8.0;netstandard2.0;netstandard2.1</TargetFrameworks>
<NoWarn>$(NoWarn);CA1716;CA2225;IDE0032;CA1866;CA2249;IDE0056;IDE0057</NoWarn>
<!-- This library intentionally exposes a different public surface per TFM (Span-based APIs on
netstandard2.1/net, Polyfill shims on older TFMs). ktsu.Sdk 2.11.0 enables strict ApiCompat
package validation, whose compatible-frameworks check (CP0006/CP0014/CP0016) cannot accept
those by-design differences. Disable it. -->
<EnablePackageValidation>false</EnablePackageValidation>
<!-- Package validation is on (ktsu.Sdk default). This library intentionally exposes a different
public surface per TFM (Polyfill shims on older TFMs differ from the in-box types), which is
why ktsu.Sdk 2.12.0+ leaves strict compatible-framework validation off; the residual
by-design differences are captured in CompatibilitySuppressions.xml. Regenerate that file
with: dotnet pack -p:ApiCompatGenerateSuppressionFile=true -->
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Polyfill" PrivateAssets="all" />
Expand Down
Loading
Loading