Skip to content

Commit

Permalink
Added GeneratedIdentifier.
Browse files Browse the repository at this point in the history
  • Loading branch information
jscarle committed Oct 24, 2024
1 parent 590706e commit 7879ba6
Show file tree
Hide file tree
Showing 40 changed files with 3,791 additions and 7 deletions.
5 changes: 5 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,5 +60,10 @@ jobs:
dotnet build ./src/LightResults.Extensions.Json/LightResults.Extensions.Json.csproj --configuration Release --no-restore
dotnet pack ./src/LightResults.Extensions.Json/LightResults.Extensions.Json.csproj --configuration Release --no-build --output .
- name: Pack GeneratedIdentifier
run: |
dotnet build ./src/LightResults.Extensions.Json/LightResults.Extensions.GeneratedIdentifier.csproj --configuration Release --no-restore
dotnet pack ./src/LightResults.Extensions.Json/LightResults.Extensions.GeneratedIdentifier.csproj --configuration Release --no-build --output .
- name: Push to NuGet
run: dotnet nuget push "*.nupkg" --api-key ${{secrets.NUGET_API_KEY}} --source https://api.nuget.org/v3/index.json --skip-duplicate
10 changes: 5 additions & 5 deletions ComparisonBenchmarks/ComparisonBenchmarks.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.13.12" />
<PackageReference Include="FluentResults" Version="3.16.0" />
<PackageReference Include="JetBrains.Annotations" Version="2023.3.0"/>
<PackageReference Include="Rascal" Version="1.1.0" />
<PackageReference Include="BenchmarkDotNet" Version="0.14.0"/>
<PackageReference Include="FluentResults" Version="3.16.0"/>
<PackageReference Include="JetBrains.Annotations" Version="2024.2.0"/>
<PackageReference Include="Rascal" Version="1.1.0"/>
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\src\LightResults.Extensions.Operations\LightResults.Extensions.Operations.csproj" />
<ProjectReference Include="..\src\LightResults.Extensions.Operations\LightResults.Extensions.Operations.csproj"/>
</ItemGroup>

</Project>
20 changes: 20 additions & 0 deletions LightResults.Extensions.sln
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Benchmarks", "tools\Benchma
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LightResults.Extensions.Operations.Tests", "tests\LightResults.Extensions.Operations.Tests\LightResults.Extensions.Operations.Tests.csproj", "{D4E8F259-596E-412D-A757-769383865764}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LightResults.Extensions.GeneratedIdentifier", "src\LightResults.Extensions.GeneratedIdentifier\LightResults.Extensions.GeneratedIdentifier.csproj", "{2D558C96-F052-4959-B996-5B03A66E4FCF}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LightResults.Extensions.GeneratedIdentifier.Fixtures", "tests\LightResults.Extensions.GeneratedIdentifier.Fixtures\LightResults.Extensions.GeneratedIdentifier.Fixtures.csproj", "{06BDEA4C-9036-44B7-AB44-DBD088556726}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LightResults.Extensions.GeneratedIdentifier.Tests", "tests\LightResults.Extensions.GeneratedIdentifier.Tests\LightResults.Extensions.GeneratedIdentifier.Tests.csproj", "{45AF3136-2F1A-48C5-A76F-52635D7F0B90}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -58,12 +64,26 @@ Global
{D4E8F259-596E-412D-A757-769383865764}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D4E8F259-596E-412D-A757-769383865764}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D4E8F259-596E-412D-A757-769383865764}.Release|Any CPU.Build.0 = Release|Any CPU
{2D558C96-F052-4959-B996-5B03A66E4FCF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2D558C96-F052-4959-B996-5B03A66E4FCF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2D558C96-F052-4959-B996-5B03A66E4FCF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2D558C96-F052-4959-B996-5B03A66E4FCF}.Release|Any CPU.Build.0 = Release|Any CPU
{06BDEA4C-9036-44B7-AB44-DBD088556726}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{06BDEA4C-9036-44B7-AB44-DBD088556726}.Debug|Any CPU.Build.0 = Debug|Any CPU
{06BDEA4C-9036-44B7-AB44-DBD088556726}.Release|Any CPU.ActiveCfg = Release|Any CPU
{06BDEA4C-9036-44B7-AB44-DBD088556726}.Release|Any CPU.Build.0 = Release|Any CPU
{45AF3136-2F1A-48C5-A76F-52635D7F0B90}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{45AF3136-2F1A-48C5-A76F-52635D7F0B90}.Debug|Any CPU.Build.0 = Debug|Any CPU
{45AF3136-2F1A-48C5-A76F-52635D7F0B90}.Release|Any CPU.ActiveCfg = Release|Any CPU
{45AF3136-2F1A-48C5-A76F-52635D7F0B90}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{93C8BC67-7F34-4935-A671-F0B12AEDB072} = {A6C9FED0-42B6-488C-8961-DE13F291434B}
{B46CE763-0606-4497-89B7-8FB653D5031D} = {D10E009A-B3B8-4FB3-8B01-F21C383CD513}
{93C8BC67-7F34-4935-A671-F0B12AEDB072} = {A6C9FED0-42B6-488C-8961-DE13F291434B}
{6DC31D8F-B71A-4A08-A892-5593F54EB82C} = {D10E009A-B3B8-4FB3-8B01-F21C383CD513}
{D4E8F259-596E-412D-A757-769383865764} = {A6C9FED0-42B6-488C-8961-DE13F291434B}
{06BDEA4C-9036-44B7-AB44-DBD088556726} = {A6C9FED0-42B6-488C-8961-DE13F291434B}
{45AF3136-2F1A-48C5-A76F-52635D7F0B90} = {A6C9FED0-42B6-488C-8961-DE13F291434B}
EndGlobalSection
EndGlobal
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ Extensions for [LightResults](https://github.com/jscarle/LightResults), an extre
[![nuget](https://img.shields.io/nuget/v/LightResults.Extensions.Json)](https://www.nuget.org/packages/LightResults.Extensions.Json)
[![downloads](https://img.shields.io/nuget/dt/LightResults.Extensions.Json)](https://www.nuget.org/packages/LightResults.Extensions.Json)

- [Json](https://jscarle.github.io/LightResults.Extensions/docs/generatedidentifier.html) - Provides strongly-typed identifiers.

[![nuget](https://img.shields.io/nuget/v/LightResults.Extensions.GeneratedIdentifier)](https://www.nuget.org/packages/LightResults.Extensions.GeneratedIdentifier)
[![downloads](https://img.shields.io/nuget/dt/LightResults.Extensions.GeneratedIdentifier)](https://www.nuget.org/packages/LightResults.Extensions.GeneratedIdentifier)

## Documentation

Make sure to [read the docs](https://jscarle.github.io/LightResults.Extensions/) for the full API.
7 changes: 7 additions & 0 deletions docfx/docs/generatedidentifier.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# GeneratedIdentifier

A Roslyn source generator that provides strongly-typed identifiers using LightResults.

[![main](https://img.shields.io/github/actions/workflow/status/jscarle/LightResults.Extensions/main.yml?logo=github)](https://github.com/jscarle/LightResults.Extensions)
[![nuget](https://img.shields.io/nuget/v/LightResults.Extensions.GeneratedIdentifier)](https://www.nuget.org/packages/LightResults.Extensions.GeneratedIdentifier)
[![downloads](https://img.shields.io/nuget/dt/LightResults.Extensions.GeneratedIdentifier)](https://www.nuget.org/packages/LightResults.Extensions.GeneratedIdentifier)
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
namespace LightResults.Extensions.GeneratedIdentifier.Common;

/// <summary>Represents a declaration.</summary>
public sealed record Declaration
{
/// <summary>Initializes a new instance of the <see cref="Declaration"/> class with the specified type, name, and generic parameters.</summary>
/// <param name="type">The type of declaration.</param>
/// <param name="name">The name of the declaration.</param>
/// <param name="genericParameters">A read-only list of generic parameter names, or an empty list if not generic.</param>
internal Declaration(DeclarationType type, string name, EquatableImmutableArray<string> genericParameters)
{
Type = type;
Name = name;
GenericParameters = genericParameters;
}

/// <summary>Gets the type of declaration.</summary>
public DeclarationType Type { get; }

/// <summary>Gets the name of the declaration.</summary>
public string Name { get; }

/// <summary>Gets a read-only list of generic parameter names for generic declarations, or an empty list otherwise.</summary>
public EquatableImmutableArray<string> GenericParameters { get; }

/// <summary>Returns a string representation of the declaration in the appropriate format for its type.</summary>
/// <returns>A string representation of the declaration.</returns>
public override string ToString()
{
switch (Type)
{
case DeclarationType.Namespace:
return $"namespace {Name}";
case DeclarationType.Interface:
case DeclarationType.Class:
case DeclarationType.Record:
case DeclarationType.Struct:
case DeclarationType.RecordStruct:
var keyword = ToKeyword(Type);
return GenericParameters.Count == 0 ? $"{keyword} {Name}" : $"{keyword} {Name}<{string.Join(", ", GenericParameters)}>";
default:
return base.ToString();
}
}

private static string ToKeyword(DeclarationType declarationType)
{
return declarationType switch
{
DeclarationType.Namespace => "namespace",
DeclarationType.Interface => "interface",
DeclarationType.Class => "class",
DeclarationType.Record => "record",
DeclarationType.Struct => "struct",
DeclarationType.RecordStruct => "record struct",
_ => throw new InvalidOperationException(),
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
using System.Text;

namespace LightResults.Extensions.GeneratedIdentifier.Common;

/// <summary>Provides extension methods for working with declarations.</summary>
internal static class DeclarationExtensions
{
/// <summary>Converts a list of declarations to their corresponding namespace.</summary>
/// <param name="declarations">The list of declarations to convert.</param>
/// <returns>The namespace represented by the declarations.</returns>
public static string ToNamespace(this EquatableImmutableArray<Declaration> declarations)
{
var builder = new StringBuilder();

for (var index = 0; index < declarations.Count; index++)
{
var declaration = declarations[index];
if (declaration.Type != DeclarationType.Namespace)
continue;

if (builder.Length > 0)
builder.Append('.');
builder.Append(declaration.Name);
}

return builder.ToString();
}

/// <summary>Converts a list of declarations to their fully qualified name.</summary>
/// <param name="declarations">The list of declarations to convert.</param>
/// <returns>The fully qualified name represented by the declarations.</returns>
public static string ToFullyQualifiedName(this EquatableImmutableArray<Declaration> declarations)
{
var builder = new StringBuilder();

for (var index = 0; index < declarations.Count; index++)
{
var declaration = declarations[index];

if (builder.Length > 0)
builder.Append('.');
builder.Append(declaration.Name);

if (declaration.GenericParameters.Count == 0)
continue;

builder.Append('`');
builder.Append(declaration.GenericParameters.Count);
}

return builder.ToString();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
namespace LightResults.Extensions.GeneratedIdentifier.Common;

/// <summary>Specifies the kind of declaration.</summary>
public enum DeclarationType
{
/// <summary>Represents a namespace declaration.</summary>
Namespace = 0,

/// <summary>Represents an interface declaration.</summary>
Interface = 1,

/// <summary>Represents a class declaration.</summary>
Class = 2,

/// <summary>Represents a record declaration.</summary>
Record = 3,

/// <summary>Represents a struct declaration.</summary>
Struct = 4,

/// <summary>Represents a record struct declaration.</summary>
RecordStruct = 5,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System.Collections.Immutable;

namespace LightResults.Extensions.GeneratedIdentifier.Common;

/// <summary>Provides extension methods to convert various collections to an <see cref="EquatableImmutableArray{T}"/>.</summary>
internal static class EquatableImmutableArray
{
/// <summary>Converts an <see cref="IEnumerable{T}"/> to an <see cref="EquatableImmutableArray{T}"/>.</summary>
/// <param name="enumerable">The <see cref="IEnumerable{T}"/> to convert.</param>
/// <returns>An <see cref="EquatableImmutableArray{T}"/> containing the same elements as the original enumerable.</returns>
public static EquatableImmutableArray<T> ToEquatableImmutableArray<T>(this IEnumerable<T> enumerable)
{
return new EquatableImmutableArray<T>(enumerable.ToImmutableArray());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
using System.Collections;
using System.Collections.Immutable;

namespace LightResults.Extensions.GeneratedIdentifier.Common;

/// <summary>Represents an immutable array that implements <see cref="IEquatable{T}"/>.</summary>
/// <typeparam name="T">The type of elements in the array.</typeparam>
public readonly struct EquatableImmutableArray<T> : IEquatable<EquatableImmutableArray<T>>, IReadOnlyList<T>
{
/// <summary>Gets an empty <see cref="EquatableImmutableArray{T}"/>.</summary>
internal static EquatableImmutableArray<T> Empty { get; } = new(ImmutableArray<T>.Empty);

/// <summary>Gets the number of elements in the array.</summary>
public int Count => Array.Length;

/// <summary>Gets the element at the specified index.</summary>
/// <param name="index">The zero-based index of the element to get.</param>
/// <returns>The element at the specified index.</returns>
public T this[int index] => Array[index];

private ImmutableArray<T> Array => _array ?? ImmutableArray<T>.Empty;
private readonly ImmutableArray<T>? _array;

internal EquatableImmutableArray(ImmutableArray<T>? array)
{
_array = array;
}

/// <inheritdoc/>
public bool Equals(EquatableImmutableArray<T> other)
{
return this.SequenceEqual(other);
}

/// <inheritdoc/>
public override bool Equals(object? obj)
{
return obj is EquatableImmutableArray<T> other && Equals(other);
}

/// <inheritdoc/>
public override int GetHashCode()
{
var hashCode = new HashCode();

foreach (var item in Array)
hashCode.Add(item);

return hashCode.ToHashCode();
}

/// <summary>Determines whether two <see cref="EquatableImmutableArray{T}"/> instances are equal.</summary>
/// <param name="left">The first <see cref="EquatableImmutableArray{T}"/> to compare.</param>
/// <param name="right">The second <see cref="EquatableImmutableArray{T}"/> to compare.</param>
/// <returns><see langword="true"/> if the two <see cref="EquatableImmutableArray{T}"/> instances are equal; otherwise, <see langword="false"/>.</returns>
public static bool operator ==(EquatableImmutableArray<T> left, EquatableImmutableArray<T> right)
{
return left.Equals(right);
}

/// <summary>Determines whether two <see cref="EquatableImmutableArray{T}"/> instances are not equal.</summary>
/// <param name="left">The first <see cref="EquatableImmutableArray{T}"/> to compare.</param>
/// <param name="right">The second <see cref="EquatableImmutableArray{T}"/> to compare.</param>
/// <returns><see langword="true"/> if the two <see cref="EquatableImmutableArray{T}"/> instances are not equal; otherwise, <see langword="false"/>.</returns>
public static bool operator !=(EquatableImmutableArray<T> left, EquatableImmutableArray<T> right)
{
return !left.Equals(right);
}

/// <inheritdoc/>
public IEnumerator<T> GetEnumerator()
{
// ReSharper disable once ForCanBeConvertedToForeach
// ReSharper disable once LoopCanBeConvertedToQuery
for (var index = 0; index < Array.Length; index++)
{
var item = Array[index];
yield return item;
}
}

/// <inheritdoc/>
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using Microsoft.CodeAnalysis;

namespace LightResults.Extensions.GeneratedIdentifier.Common;

internal static class IncrementalValueProviderExtensions
{
public static IncrementalValuesProvider<TSource> WhereNotNull<TSource>(this IncrementalValuesProvider<TSource?> source)
where TSource : struct
{
return source.Where(x => x is not null)
.Select((x, _) => x!.Value);
}
}
Loading

0 comments on commit 7879ba6

Please sign in to comment.