Skip to content

Commit

Permalink
Fundamental redesign to allow complete customisation (#117)
Browse files Browse the repository at this point in the history
* Use ForAttributeWithMetadataName APIs

Fix duplicate test problem
Add new diagnostic for duplicate assembly attributes

* wip

* wip

* Add long and .net 8 support

* Add string (and fix bugs)

* Add Nullable String

* Add NewId template

* Update snapshots

* Lots of fixes

* Fix packaging (and remove other package)

* Delete old files

* Remove unused diagnostics

* Add invalid template name diagnostic

* Update handling of unknown templates (adds a diagnostic)

* Don't do special behaviour for custom templates + add diagnostic for invalid templates

* Add codefixprovider (need to try it)

* Fix nullability warning

* Make the analyzer return an error instead

* Revert accidental hacking aroudn

* Make nullable ID an extended type

* Move to separate templates NuGet folder

* Add some optional "partial" templates

* Try to fix tests

* Remove the built-in templates from the generator tests

They just add noise

* Support adding multiple templates in one attribute

* Add unit tests for multiple templates

* Fix StringBuilder re-use bug

* Add missing templates

* Add guid converter templates tests

* Add LongId tests

* Add string integration tests

* Fix typos

* Update diagnostics to ensure unique (breaking change)

* Remove unused includes

* Fix templates package

* Show the additional templates in the project

* Add 8.0.x to Github actions

* Tweak codefix action

* Fix windows-specific paths

* Ensure we test both in-project IDs and "external" IDs

* Make all the converts public by default

It doesn't really make sense that their not...

* Add source generator tests for GuidIds

* Use Ordinal Comparisons instead of culture-specific in string IDs

* Add test for the nullable

* Make all converters partial

* Add comparison operators

* Fix typo
  • Loading branch information
andrewlock authored Nov 15, 2023
1 parent 69473c3 commit 63d6de0
Show file tree
Hide file tree
Showing 225 changed files with 10,226 additions and 12,031 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/BuildAndPack.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ jobs:
- uses: actions/setup-dotnet@v3
with:
dotnet-version: |
8.0.x
7.0.x
6.0.x
5.0.x
Expand Down Expand Up @@ -66,6 +67,7 @@ jobs:
- uses: actions/setup-dotnet@v3
with:
dotnet-version: |
8.0.x
7.0.x
6.0.x
5.0.x
Expand Down Expand Up @@ -96,6 +98,7 @@ jobs:
- uses: actions/setup-dotnet@v3
with:
dotnet-version: |
8.0.x
7.0.x
6.0.x
5.0.x
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -245,3 +245,6 @@ ModelManifest.xml
.fake/
tools/*
!tools/packages.config

# NuGet testing
globalPackagesFolder
12 changes: 12 additions & 0 deletions NuGet.integration-tests.config
Original file line number Diff line number Diff line change
@@ -1,8 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<config>
<add key="globalPackagesFolder" value="globalPackagesFolder" />
</config>
<packageSources>
<clear />
<add key="local-packages" value="./artifacts" />
<add key="nuget" value="https://api.nuget.org/v3/index.json" />
</packageSources>
<packageSourceMapping>
<packageSource key="nuget">
<package pattern="*" />
</packageSource>
<packageSource key="local-packages">
<package pattern="StronglyTypedId" />
<package pattern="StronglyTypedId.*" />
</packageSource>
</packageSourceMapping>
</configuration>
45 changes: 45 additions & 0 deletions StronglyTypedId.sln
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StronglyTypedIds.Nuget.Inte
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StronglyTypedIds.Nuget.Attributes.IntegrationTests", "test\StronglyTypedIds.Nuget.Attributes.IntegrationTests\StronglyTypedIds.Nuget.Attributes.IntegrationTests.csproj", "{19A9B323-8C0B-4D1B-A20C-8CECFFD37F23}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StronglyTypedIds.Templates", "src\StronglyTypedIds.Templates\StronglyTypedIds.Templates.csproj", "{336D7EE4-90BA-4BFC-99F6-D70B8D494E8C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StronglyTypedIds.IntegrationTests.Types", "test\StronglyTypedIds.IntegrationTests.Types\StronglyTypedIds.IntegrationTests.Types.csproj", "{A5804404-E5A5-4F05-86E2-B2A11D370498}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StronglyTypedIds.IntegrationTests.ExternalIds", "test\StronglyTypedIds.IntegrationTests.ExternalIds\StronglyTypedIds.IntegrationTests.ExternalIds.csproj", "{07875BB0-EFEE-4F90-AAB8-4B11F78C8047}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -104,6 +110,42 @@ Global
{19A9B323-8C0B-4D1B-A20C-8CECFFD37F23}.Release|Any CPU.ActiveCfg = Release|Any CPU
{19A9B323-8C0B-4D1B-A20C-8CECFFD37F23}.Release|x64.ActiveCfg = Release|Any CPU
{19A9B323-8C0B-4D1B-A20C-8CECFFD37F23}.Release|x86.ActiveCfg = Release|Any CPU
{336D7EE4-90BA-4BFC-99F6-D70B8D494E8C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{336D7EE4-90BA-4BFC-99F6-D70B8D494E8C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{336D7EE4-90BA-4BFC-99F6-D70B8D494E8C}.Debug|x64.ActiveCfg = Debug|Any CPU
{336D7EE4-90BA-4BFC-99F6-D70B8D494E8C}.Debug|x64.Build.0 = Debug|Any CPU
{336D7EE4-90BA-4BFC-99F6-D70B8D494E8C}.Debug|x86.ActiveCfg = Debug|Any CPU
{336D7EE4-90BA-4BFC-99F6-D70B8D494E8C}.Debug|x86.Build.0 = Debug|Any CPU
{336D7EE4-90BA-4BFC-99F6-D70B8D494E8C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{336D7EE4-90BA-4BFC-99F6-D70B8D494E8C}.Release|Any CPU.Build.0 = Release|Any CPU
{336D7EE4-90BA-4BFC-99F6-D70B8D494E8C}.Release|x64.ActiveCfg = Release|Any CPU
{336D7EE4-90BA-4BFC-99F6-D70B8D494E8C}.Release|x64.Build.0 = Release|Any CPU
{336D7EE4-90BA-4BFC-99F6-D70B8D494E8C}.Release|x86.ActiveCfg = Release|Any CPU
{336D7EE4-90BA-4BFC-99F6-D70B8D494E8C}.Release|x86.Build.0 = Release|Any CPU
{A5804404-E5A5-4F05-86E2-B2A11D370498}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A5804404-E5A5-4F05-86E2-B2A11D370498}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A5804404-E5A5-4F05-86E2-B2A11D370498}.Debug|x64.ActiveCfg = Debug|Any CPU
{A5804404-E5A5-4F05-86E2-B2A11D370498}.Debug|x64.Build.0 = Debug|Any CPU
{A5804404-E5A5-4F05-86E2-B2A11D370498}.Debug|x86.ActiveCfg = Debug|Any CPU
{A5804404-E5A5-4F05-86E2-B2A11D370498}.Debug|x86.Build.0 = Debug|Any CPU
{A5804404-E5A5-4F05-86E2-B2A11D370498}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A5804404-E5A5-4F05-86E2-B2A11D370498}.Release|Any CPU.Build.0 = Release|Any CPU
{A5804404-E5A5-4F05-86E2-B2A11D370498}.Release|x64.ActiveCfg = Release|Any CPU
{A5804404-E5A5-4F05-86E2-B2A11D370498}.Release|x64.Build.0 = Release|Any CPU
{A5804404-E5A5-4F05-86E2-B2A11D370498}.Release|x86.ActiveCfg = Release|Any CPU
{A5804404-E5A5-4F05-86E2-B2A11D370498}.Release|x86.Build.0 = Release|Any CPU
{07875BB0-EFEE-4F90-AAB8-4B11F78C8047}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{07875BB0-EFEE-4F90-AAB8-4B11F78C8047}.Debug|Any CPU.Build.0 = Debug|Any CPU
{07875BB0-EFEE-4F90-AAB8-4B11F78C8047}.Debug|x64.ActiveCfg = Debug|Any CPU
{07875BB0-EFEE-4F90-AAB8-4B11F78C8047}.Debug|x64.Build.0 = Debug|Any CPU
{07875BB0-EFEE-4F90-AAB8-4B11F78C8047}.Debug|x86.ActiveCfg = Debug|Any CPU
{07875BB0-EFEE-4F90-AAB8-4B11F78C8047}.Debug|x86.Build.0 = Debug|Any CPU
{07875BB0-EFEE-4F90-AAB8-4B11F78C8047}.Release|Any CPU.ActiveCfg = Release|Any CPU
{07875BB0-EFEE-4F90-AAB8-4B11F78C8047}.Release|Any CPU.Build.0 = Release|Any CPU
{07875BB0-EFEE-4F90-AAB8-4B11F78C8047}.Release|x64.ActiveCfg = Release|Any CPU
{07875BB0-EFEE-4F90-AAB8-4B11F78C8047}.Release|x64.Build.0 = Release|Any CPU
{07875BB0-EFEE-4F90-AAB8-4B11F78C8047}.Release|x86.ActiveCfg = Release|Any CPU
{07875BB0-EFEE-4F90-AAB8-4B11F78C8047}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -115,6 +157,9 @@ Global
{F25F6E67-E62A-4075-86CF-4C4EDD7E4883} = {EE1258BD-3422-4F55-B9CF-B4D6C95DAD68}
{A7355210-7DDC-4968-84B7-79002113EA6E} = {D1907D86-8FFC-4178-A3DB-0ADBDD282C64}
{19A9B323-8C0B-4D1B-A20C-8CECFFD37F23} = {D1907D86-8FFC-4178-A3DB-0ADBDD282C64}
{336D7EE4-90BA-4BFC-99F6-D70B8D494E8C} = {EE1258BD-3422-4F55-B9CF-B4D6C95DAD68}
{A5804404-E5A5-4F05-86E2-B2A11D370498} = {D1907D86-8FFC-4178-A3DB-0ADBDD282C64}
{07875BB0-EFEE-4F90-AAB8-4B11F78C8047} = {D1907D86-8FFC-4178-A3DB-0ADBDD282C64}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {8D1F0534-B8AD-4CFA-9C14-CBC757BCB1E1}
Expand Down
65 changes: 33 additions & 32 deletions src/StronglyTypedIds.Attributes/StronglyTypedIdAttribute.cs
Original file line number Diff line number Diff line change
@@ -1,48 +1,49 @@
using System;
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by the StronglyTypedId source generator
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

#pragma warning disable 1591 // publicly visible type or member must be documented

#nullable enable

namespace StronglyTypedIds
{
/// <summary>
/// Place on partial structs to make the type a strongly-typed ID
/// </summary>
[AttributeUsage(AttributeTargets.Struct, Inherited = false, AllowMultiple = false)]
[System.Diagnostics.Conditional("STRONGLY_TYPED_ID_USAGES")]
public sealed class StronglyTypedIdAttribute : Attribute
[global::System.AttributeUsage(global::System.AttributeTargets.Struct, Inherited = false, AllowMultiple = false)]
[global::System.Diagnostics.Conditional("STRONGLY_TYPED_ID_USAGES")]
public sealed class StronglyTypedIdAttribute : global::System.Attribute
{
/// <summary>
/// Make the struct a strongly typed ID
/// Make the struct a strongly typed ID.
/// </summary>
/// <param name="backingType">The <see cref="Type"/> to use to store the strongly-typed ID value.
/// If not set, uses <see cref="StronglyTypedIdDefaultsAttribute.BackingType"/>, which defaults to <see cref="StronglyTypedIdBackingType.Guid"/></param>
/// <param name="converters">Converters to create for serializing/deserializing the strongly-typed ID value.
/// If not set, uses <see cref="StronglyTypedIdDefaultsAttribute.Converters"/>, which defaults to <see cref="StronglyTypedIdConverter.NewtonsoftJson"/>
/// and <see cref="StronglyTypedIdConverter.TypeConverter"/></param>
/// <param name="implementations">Interfaces and patterns the strongly typed id should implement
/// If not set, uses <see cref="StronglyTypedIdDefaultsAttribute.Implementations"/>, which defaults to <see cref="StronglyTypedIdImplementations.IEquatable"/>
/// and <see cref="StronglyTypedIdImplementations.IComparable"/></param>
public StronglyTypedIdAttribute(
StronglyTypedIdBackingType backingType = StronglyTypedIdBackingType.Default,
StronglyTypedIdConverter converters = StronglyTypedIdConverter.Default,
StronglyTypedIdImplementations implementations = StronglyTypedIdImplementations.Default)
/// <param name="template">The built-in template to use to generate the ID.</param>
/// <param name="templateNames">The names of additional custom templates to use to generate the ID.
/// Templates must be added to the project using the format NAME.typedid,
/// where NAME is the name of the template passed in <paramref name="templateNames"/>.
/// </param>
public StronglyTypedIdAttribute(global::StronglyTypedIds.Template template, params string[] templateNames)
{
BackingType = backingType;
Converters = converters;
Implementations = implementations;
}

/// <summary>
/// The <see cref="Type"/> to use to store the strongly-typed ID value
/// </summary>
public StronglyTypedIdBackingType BackingType { get; }

/// <summary>
/// JSON library used to serialize/deserialize strongly-typed ID value
/// Make the struct a strongly typed ID.
/// </summary>
public StronglyTypedIdConverter Converters { get; }

/// <summary>
/// Interfaces and patterns the strongly typed id should implement
/// </summary>
public StronglyTypedIdImplementations Implementations { get; }
/// <param name="templateNames">The names of the template to use to generate the ID.
/// Templates must be added to the project using the format NAME.typedid,
/// where NAME is the name of the template passed in <paramref name="templateNames"/>.
/// If no templates are provided, the default value is used, as specified by
/// <see cref="StronglyTypedIdDefaultsAttribute"/>, or alternatively the
/// <see cref="Template.Guid"/> template.
/// </param>
public StronglyTypedIdAttribute(params string[] templateNames)
{
}
}
}
22 changes: 0 additions & 22 deletions src/StronglyTypedIds.Attributes/StronglyTypedIdBackingType.cs

This file was deleted.

50 changes: 0 additions & 50 deletions src/StronglyTypedIds.Attributes/StronglyTypedIdConverter.cs

This file was deleted.

68 changes: 40 additions & 28 deletions src/StronglyTypedIds.Attributes/StronglyTypedIdDefaultsAttribute.cs
Original file line number Diff line number Diff line change
@@ -1,46 +1,58 @@
using System;
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by the StronglyTypedId source generator
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

#pragma warning disable 1591 // publicly visible type or member must be documented

#nullable enable

namespace StronglyTypedIds
{
/// <summary>
/// Used to control the default Place on partial structs to make the type a strongly-typed ID
/// Used to control the default strongly typed ID values. Apply to an assembly using
/// <code>[assembly:StronglyTypedIdDefaults(Template.Int)]</code> for example
/// </summary>
[AttributeUsage(AttributeTargets.Assembly, Inherited = false, AllowMultiple = false)]
[System.Diagnostics.Conditional("STRONGLY_TYPED_ID_USAGES")]
public sealed class StronglyTypedIdDefaultsAttribute : Attribute
[global::System.AttributeUsage(global::System.AttributeTargets.Assembly, Inherited = false, AllowMultiple = false)]
[global::System.Diagnostics.Conditional("STRONGLY_TYPED_ID_USAGES")]
public sealed class StronglyTypedIdDefaultsAttribute : global::System.Attribute
{
/// <summary>
/// Set the default values used for strongly typed ids
/// Set the default template to use for strongly typed IDs
/// </summary>
/// <param name="backingType">The <see cref="Type"/> to use to store the strongly-typed ID value.
/// Defaults to <see cref="StronglyTypedIdBackingType.Guid"/></param>
/// <param name="converters">JSON library used to serialize/deserialize strongly-typed ID value.
/// Defaults to <see cref="StronglyTypedIdConverter.NewtonsoftJson"/> and <see cref="StronglyTypedIdConverter.TypeConverter"/></param>
/// <param name="implementations">Interfaces and patterns the strongly typed id should implement
/// Defaults to <see cref="StronglyTypedIdImplementations.IEquatable"/> and <see cref="StronglyTypedIdImplementations.IComparable"/></param>
public StronglyTypedIdDefaultsAttribute(
StronglyTypedIdBackingType backingType = StronglyTypedIdBackingType.Default,
StronglyTypedIdConverter converters = StronglyTypedIdConverter.Default,
StronglyTypedIdImplementations implementations = StronglyTypedIdImplementations.Default)
/// <param name="template">The built-in template to use to generate the ID.</param>
/// <param name="templateNames">The names of additional custom templates to use to generate the ID.
/// Templates must be added to the project using the format NAME.typedid,
/// where NAME is the name of the template passed in <paramref name="templateNames"/>.
/// </param>
public StronglyTypedIdDefaultsAttribute(global::StronglyTypedIds.Template template, params string[] templateNames)
{
BackingType = backingType;
Converters = converters;
Implementations = implementations;
}

/// <summary>
/// The default <see cref="Type"/> to use to store the strongly-typed ID values.
/// </summary>
public StronglyTypedIdBackingType BackingType { get; }

/// <summary>
/// The default converters to create for serializing/deserializing strongly-typed ID values.
/// Set the default template to use for strongly typed IDs
/// </summary>
public StronglyTypedIdConverter Converters { get; }
/// <param name="templateName">The name of the template to use to generate the ID.
/// Templates must be added to the project using the format NAME.typedid,
/// where NAME is the name of the template passed in <paramref name="templateName"/>.
/// </param>
public StronglyTypedIdDefaultsAttribute(string templateName)
{
}

/// <summary>
/// Interfaces and patterns the strongly typed id should implement
/// Set the default template to use for strongly typed IDs
/// </summary>
public StronglyTypedIdImplementations Implementations { get; }
/// <param name="templateName">The name of the template to use to generate the ID.
/// Templates must be added to the project using the format NAME.typedid,
/// where NAME is the name of the template passed in <paramref name="templateName"/>.
/// </param>
public StronglyTypedIdDefaultsAttribute(string templateName, params string[] templateNames)
{
}
}
}
Loading

0 comments on commit 63d6de0

Please sign in to comment.