Skip to content

Commit 2703593

Browse files
committed
Merge branch 'release/1.1.0'
2 parents 103156d + 458760a commit 2703593

31 files changed

+1821
-437
lines changed

.github/workflows/ci.yml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ on:
55
branches:
66
- main
77
- develop
8+
tags:
9+
- '*.*.*'
810
pull_request:
911
branches:
1012
- main
@@ -14,6 +16,7 @@ on:
1416
permissions:
1517
checks: write
1618
statuses: write
19+
contents: write
1720

1821
jobs:
1922
build:
@@ -40,3 +43,19 @@ jobs:
4043

4144
- name: Run tests
4245
run: dotnet test --configuration $BUILD_CONFIG --no-restore --no-build --verbosity normal
46+
47+
- name: Pack NuGet package
48+
if: startsWith(github.ref, 'refs/tags/')
49+
run: dotnet pack $SOLUTION --configuration $BUILD_CONFIG --no-build --output ./artifacts
50+
51+
- name: Publish to NuGet
52+
if: startsWith(github.ref, 'refs/tags/')
53+
run: dotnet nuget push ./artifacts/*.nupkg --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json --skip-duplicate
54+
55+
- name: Create GitHub Release
56+
if: startsWith(github.ref, 'refs/tags/')
57+
uses: softprops/action-gh-release@v1
58+
with:
59+
generate_release_notes: true
60+
env:
61+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,17 @@
11
Changelog
22
---
33

4+
## v1.1.0
5+
Release Date: 2025-06-29
6+
7+
### Features
8+
- Rewrote the generator pipeline to improve performance, and only regenerate when additional texts are changed (resolves #4)
9+
- Added support for nested classes and generics (resolves #3)
10+
- Made integration easier by automatically including EmbeddedResources as Additional Text Files
11+
- Lowered the minimum version of Microsoft.CodeAnalysis.CSharp required to support older .NET versions
12+
13+
**Full Changelog**: https://github.com/datacute/EmbeddedResourcePropertyGenerator/compare/1.0.0...1.1.0
14+
415
## v1.0.0
516
Release Date: 2024-10-28
617

Directory.Build.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
<PropertyGroup>
66
<Authors>Stephen Denne</Authors>
7-
<Copyright>Copyright © Stephen Denne 2024</Copyright>
7+
<Copyright>Copyright © Stephen Denne 2024, 2025</Copyright>
88
<Company>Datacute</Company>
99
<PackageProjectUrl>https://github.com/datacute/EmbeddedResourcePropertyGenerator</PackageProjectUrl>
1010
<CheckEolTargetFramework>false</CheckEolTargetFramework>

EmbeddedResourceProperty.sln

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
1717
version.props = version.props
1818
LICENSE = LICENSE
1919
README.md = README.md
20+
Pipelines.md = Pipelines.md
2021
EndProjectSection
2122
EndProject
2223
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EmbeddedResourcePropertyGenerator.Attributes", "EmbeddedResourcePropertyGenerator.Attributes\EmbeddedResourcePropertyGenerator.Attributes.csproj", "{73A7F255-8275-41A3-8A2A-E70FE85DD0B5}"

EmbeddedResourcePropertyExample/EmbeddedResourcePropertyExample.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
</PropertyGroup>
1313

1414
<ItemGroup>
15-
<ProjectReference Include="..\EmbeddedResourcePropertyGenerator.Attributes\EmbeddedResourcePropertyGenerator.Attributes.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="true" />
15+
<ProjectReference Include="..\EmbeddedResourcePropertyGenerator.Attributes\EmbeddedResourcePropertyGenerator.Attributes.csproj" />
1616
<ProjectReference Include="..\EmbeddedResourcePropertyGenerator\EmbeddedResourcePropertyGenerator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
1717
</ItemGroup>
1818

EmbeddedResourcePropertyExample/Program.cs

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,16 @@
3232
Console.WriteLine(SqlQueryOverrides.SelectAll);
3333
Console.WriteLine();
3434

35+
Console.WriteLine("Example of using the attribute in an inner class:");
36+
Console.WriteLine("First call, the backing field value will be set:");
37+
Console.WriteLine(SqlQueryOverrides.SqlQueries.SelectAll);
38+
Console.WriteLine();
39+
Console.WriteLine("Second call, the backing field already has a value:");
40+
Console.WriteLine(SqlQueryOverrides.SqlQueries.SelectAll);
41+
Console.WriteLine();
3542

36-
[EmbeddedResourceProperties(".sql", "SqlQueries")]
43+
44+
[EmbeddedResourceProperties(Extension = ".sql", Path = "SqlQueries")]
3745
static partial class SqlQuery;
3846

3947

@@ -64,4 +72,19 @@ static partial void ReadEmbeddedResourceValue(
6472
backingField = "SELECT * FROM NewCustomersView;";
6573
}
6674
}
67-
}
75+
76+
// When no path is specified, the name of the class is used as the folder to search,
77+
// relative to the folder that this file is in.
78+
// When the class is an inner class, none of the parent class names are included
79+
// i.e. The directory searched will be "SqlQueries", not "SqlQueryOverrides.SqlQueries"
80+
[EmbeddedResourceProperties(".sql")]
81+
public static partial class SqlQueries
82+
{
83+
}
84+
}
85+
86+
[EmbeddedResourceProperties] // there are no matching ".txt" files
87+
static partial class SqlQueries;
88+
89+
[EmbeddedResourceProperties(".NoMatch", DiagnosticTraceLog = true)]
90+
static partial class JustShowTheDiagnosticsLog;

EmbeddedResourcePropertyGenerator.Attributes/EmbeddedResourcePropertiesAttribute.cs

Lines changed: 51 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
using System;
22

3+
// ReSharper disable UnusedParameter.Local
4+
// ReSharper disable UnusedAutoPropertyAccessor.Global
5+
36
namespace Datacute.EmbeddedResourcePropertyGenerator;
47

58
/// <summary>
69
/// Use a source generator to add properties to this class for each embedded resource file
7-
/// with a filename matching the given <see cref="Extension"/>
8-
/// found in the given <see cref="Path"/>.
10+
/// with a filename matching the given <see cref="Extension">Extension</see>
11+
/// found in the given <see cref="Path">Path</see>.
912
/// <para>
1013
/// If the path starts with "/" it is relative to the project root,
1114
/// otherwise it is relative to the folder containing the class with this attribute.
@@ -14,16 +17,6 @@ namespace Datacute.EmbeddedResourcePropertyGenerator;
1417
/// </summary>
1518
/// <remarks>
1619
/// <para>
17-
/// Source generators only have access to <c>AdditionalFiles</c>.
18-
/// All <c>EmbeddedResource</c> files can be automatically included as <c>AdditionalFiles</c>
19-
/// by including the following line in the project file:
20-
/// <code>
21-
/// &lt;ItemGroup&gt;
22-
/// &lt;AdditionalFileItemNames&gt;$(AdditionalFileItemNames);EmbeddedResource&lt;/AdditionalFileItemNames&gt;
23-
/// &lt;/ItemGroup&gt;
24-
/// </code>
25-
/// </para>
26-
/// <para>
2720
/// The generated code includes a private nested class <c>EmbeddedResource</c> containing:
2821
/// <list type="table">
2922
/// <listheader><term>Method or Class</term><description>Purpose</description></listheader>
@@ -84,7 +77,7 @@ public sealed class EmbeddedResourcePropertiesAttribute : Attribute
8477
{
8578
/// <value>The filename extension of the embedded resource files
8679
/// to include as properties, defaulting to ".txt".</value>
87-
public string Extension { get; private set; }
80+
public string Extension { get; set; }
8881

8982
/// <value>The path of the directory of embedded resource files
9083
/// to include as properties.</value>
@@ -93,8 +86,52 @@ public sealed class EmbeddedResourcePropertiesAttribute : Attribute
9386
/// otherwise it is relative to the folder containing the class with this attribute.
9487
/// If the path is not specified, the class name is used.
9588
/// </remarks>
96-
public string? Path { get; private set; }
89+
public string? Path { get; set; }
90+
91+
/// <value>
92+
/// Ignore the doc-comment cache and repeatedly read the embedded resource files to generate the doc-comments
93+
/// </value>
94+
/// <remarks>
95+
/// To include doc-comments on properties, embedded resource file are read once and the doc-comments are cached.
96+
/// The cache can be refreshed for embedded resource files matching this attributes path and extension,
97+
/// by temporarily setting this property to true.
98+
/// </remarks>
99+
public bool RegenerateDocCommentsWhileEditing { get; set; }
100+
101+
/// <value>
102+
/// Output a diagnostic trace log as a comment at the end of the generated files
103+
/// </value>
104+
/// <remarks>
105+
/// The log shows timestamps for each step of the Embedded Resource Property incremental source code generation process,
106+
/// </remarks>
107+
public bool DiagnosticTraceLog { get; set; }
108+
109+
/// <summary>
110+
/// Use a source generator to add properties to this class for each embedded resource file
111+
/// found in the <see cref="Path">path</see> with the folder name the same as this class,
112+
/// and where the file name's <see cref="Extension">extension</see> is ".txt"
113+
/// </summary>
114+
public EmbeddedResourcePropertiesAttribute() : this(".txt", null)
115+
{
116+
}
117+
118+
/// <summary>
119+
/// Use a source generator to add properties to this class for each embedded resource file
120+
/// found in the <see cref="Path">path</see> with the folder name the same as this class,
121+
/// and where the file name's <see cref="Extension">extension</see> matches the given extension.
122+
/// </summary>
123+
/// <param name="extension">The file name extension to include</param>
124+
public EmbeddedResourcePropertiesAttribute(string extension = ".txt") : this(extension, null)
125+
{
126+
}
97127

128+
/// <summary>
129+
/// Use a source generator to add properties to this class for each embedded resource file
130+
/// found in the specified <see cref="Path">path</see>,
131+
/// and where the file name's <see cref="Extension">extension</see> matches the given extension.
132+
/// </summary>
133+
/// <param name="extension">The file name extension to include</param>
134+
/// <param name="path">The folder path to include</param>
98135
public EmbeddedResourcePropertiesAttribute(string extension = ".txt", string? path = null)
99136
{
100137
Extension = extension;

EmbeddedResourcePropertyGenerator.Tests/EmbeddedResourcePropertyGenerator.Tests.csproj

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,30 +4,23 @@
44
<TargetFramework>net8.0</TargetFramework>
55
<ImplicitUsings>enable</ImplicitUsings>
66
<Nullable>enable</Nullable>
7+
<OutputType>Exe</OutputType>
78

89
<IsPackable>false</IsPackable>
910
<IsTestProject>true</IsTestProject>
1011
</PropertyGroup>
1112

1213
<ItemGroup>
13-
<PackageReference Include="coverlet.collector" Version="6.0.2">
14-
<PrivateAssets>all</PrivateAssets>
15-
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
16-
</PackageReference>
17-
<PackageReference Include="FluentAssertions" Version="6.12.1" />
18-
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4">
19-
<PrivateAssets>all</PrivateAssets>
20-
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
21-
</PackageReference>
22-
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.11.0" />
23-
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
24-
<PackageReference Include="Verify.SourceGenerators" Version="2.4.3" />
25-
<PackageReference Include="Verify.Xunit" Version="26.4.5" />
26-
<PackageReference Include="xunit" Version="2.9.0" />
27-
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2">
14+
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.13.0" />
15+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.13.0" />
16+
<PackageReference Include="Shouldly" Version="4.3.0" />
17+
<PackageReference Include="Verify.SourceGenerators" Version="2.5.0" />
18+
<PackageReference Include="Verify.XunitV3" Version="29.3.0" />
19+
<PackageReference Include="xunit.runner.visualstudio" Version="3.0.2">
2820
<PrivateAssets>all</PrivateAssets>
2921
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
3022
</PackageReference>
23+
<PackageReference Include="xunit.v3" Version="2.0.1" />
3124
</ItemGroup>
3225

3326
<ItemGroup>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
//HintName: OuterClass_T_.InnerClass.g.cs
2+
//------------------------------------------------------------------------------
3+
// <auto-generated>
4+
// This code was generated by the Datacute.EmbeddedResourcePropertyGenerator.
5+
// </auto-generated>
6+
//------------------------------------------------------------------------------
7+
8+
#nullable enable
9+
10+
public static partial class OuterClass<T>
11+
{
12+
/// <summary>
13+
/// This class's properties are generated from project files meeting the criteria:
14+
/// <list type="bullet">
15+
/// <item>
16+
/// <description>they are both an <c>EmbeddedResource</c> and an <c>AdditionalFile</c></description>
17+
/// </item>
18+
/// <item>
19+
/// <description>they are in the project folder <c>InnerClass</c></description>
20+
/// </item>
21+
/// <item>
22+
/// <description>they have the extension <c>.txt</c></description>
23+
/// </item>
24+
/// </list>
25+
/// </summary>
26+
public static partial class InnerClass
27+
{
28+
private static class EmbeddedResource
29+
{
30+
public static string Read(string resourceName)
31+
{
32+
var assembly = typeof(InnerClass).Assembly;
33+
using var stream = assembly.GetManifestResourceStream(resourceName)!;
34+
using var streamReader = new global::System.IO.StreamReader(stream, global::System.Text.Encoding.UTF8);
35+
var resourceText = streamReader.ReadToEnd();
36+
return resourceText;
37+
}
38+
public static class BackingField
39+
{
40+
public static string? Example;
41+
}
42+
public static class ResourceName
43+
{
44+
public const string Example = "EmbeddedResourcePropertyGenerator.Tests.InnerClass.example.txt";
45+
}
46+
}
47+
static partial void ReadEmbeddedResourceValue(ref string? backingField, string resourceName, string propertyName);
48+
static partial void AlterEmbeddedResourceReturnValue(ref string value, string resourceName, string propertyName);
49+
50+
/// <summary>Text value of the Embedded Resource: example.txt</summary>
51+
/// <value>
52+
/// <code>
53+
/// Example text content
54+
/// </code>
55+
/// </value>
56+
/// <remarks>
57+
/// The value is read from the embedded resource on first access.
58+
/// </remarks>
59+
public static string Example
60+
{
61+
get
62+
{
63+
ReadEmbeddedResourceValue(ref EmbeddedResource.BackingField.Example, EmbeddedResource.ResourceName.Example, "Example");
64+
var value = EmbeddedResource.BackingField.Example ??= EmbeddedResource.Read(EmbeddedResource.ResourceName.Example);
65+
AlterEmbeddedResourceReturnValue(ref value, EmbeddedResource.ResourceName.Example, "Example");
66+
return value;
67+
}
68+
}
69+
}
70+
}

0 commit comments

Comments
 (0)