From 6bcd0ea83e2e98e790bc973cebaecd71b7994743 Mon Sep 17 00:00:00 2001 From: Jonas Ha Date: Sat, 20 Dec 2025 10:44:26 -0500 Subject: [PATCH 01/11] docs(claude): add PR commands guide - Document how to open a PR for the current branch using a pre-defined template. - Include placeholder for command arguments. --- .claude/commands/pr.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .claude/commands/pr.md diff --git a/.claude/commands/pr.md b/.claude/commands/pr.md new file mode 100644 index 0000000..aecc2b5 --- /dev/null +++ b/.claude/commands/pr.md @@ -0,0 +1,3 @@ +# Open PR for current branch +- Use this [template](https://github.com/LayeredCraft/.github/blob/main/.github/PULL_REQUEST_TEMPLATE.md) for the PR. +- $ARGUMENTS \ No newline at end of file From 9254f359af04bc4465289699fdd4e51f5b739887 Mon Sep 17 00:00:00 2001 From: Jonas Ha Date: Sat, 20 Dec 2025 10:44:40 -0500 Subject: [PATCH 02/11] chore(config): add taskfile.yaml - Introduce taskfile.yaml for task automation support. - Provides a foundation for managing developer workflows. --- taskfile.yaml | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 taskfile.yaml diff --git a/taskfile.yaml b/taskfile.yaml new file mode 100644 index 0000000..e69de29 From 019c09ac653762b59b48fffe8b4ee8a4df8ced28 Mon Sep 17 00:00:00 2001 From: Jonas Ha Date: Sat, 20 Dec 2025 10:44:49 -0500 Subject: [PATCH 03/11] chore(project): update solution and dependencies - Add new project to solution: LayeredCraft.SourceGeneratorTools.Generator. - Update .gitignore to include .env files. - Add new package versions: Microsoft.CodeAnalysis.CSharp and Microsoft.CodeAnalysis.Analyzers. --- .gitignore | 4 +++- Directory.Packages.props | 2 ++ LayeredCraft.SourceGeneratorTools.slnx | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 61a2cff..b3eebc8 100644 --- a/.gitignore +++ b/.gitignore @@ -55,4 +55,6 @@ nunit-*.xml .idea -**/*DotSettings.user \ No newline at end of file +**/*DotSettings.user + +**/*.env \ No newline at end of file diff --git a/Directory.Packages.props b/Directory.Packages.props index 45b9ef4..0ddb11f 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -13,5 +13,7 @@ + + diff --git a/LayeredCraft.SourceGeneratorTools.slnx b/LayeredCraft.SourceGeneratorTools.slnx index 8cd28e9..63cd750 100644 --- a/LayeredCraft.SourceGeneratorTools.slnx +++ b/LayeredCraft.SourceGeneratorTools.slnx @@ -6,6 +6,7 @@ + From 0d72792d98ac25151461623d917e503c248c2bf1 Mon Sep 17 00:00:00 2001 From: Jonas Ha Date: Sat, 20 Dec 2025 10:47:26 -0500 Subject: [PATCH 04/11] chore(config): add editor and tooling configuration - Add .editorconfig for consistent code formatting across editors. - Add .config/dotnet-tools.json for managing .NET CLI tools. - Add global.json for specifying .NET SDK version and roll-forward policy. --- .config/dotnet-tools.json | 20 ++++++++++++++++++++ .editorconfig | 14 ++++++++++++++ global.json | 6 ++++++ 3 files changed, 40 insertions(+) create mode 100644 .config/dotnet-tools.json create mode 100644 .editorconfig create mode 100644 global.json diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json new file mode 100644 index 0000000..46c33a8 --- /dev/null +++ b/.config/dotnet-tools.json @@ -0,0 +1,20 @@ +{ + "version": 1, + "isRoot": true, + "tools": { + "csharpier": { + "version": "1.2.3", + "commands": [ + "csharpier" + ], + "rollForward": false + }, + "jetbrains.resharper.globaltools": { + "version": "2025.3.0.4", + "commands": [ + "jb" + ], + "rollForward": false + } + } +} \ No newline at end of file diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..f94d1a7 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,14 @@ +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 2 +max_line_length = 100 + +[*.cs] +indent_size = 4 +end_of_line = LF +insert_final_newline = true +trim_trailing_whitespace = true + diff --git a/global.json b/global.json new file mode 100644 index 0000000..38f47fa --- /dev/null +++ b/global.json @@ -0,0 +1,6 @@ +{ + "sdk": { + "rollForward": "latestMinor", + "version": "10.0.101" + } +} \ No newline at end of file From 35d127ccbc8e0149c41440a7761f5f26e6913863 Mon Sep 17 00:00:00 2001 From: Jonas Ha Date: Sat, 20 Dec 2025 10:48:59 -0500 Subject: [PATCH 05/11] chore(config): add Rider and ReSharper settings - Add LayeredCraft.SourceGeneratorTools.sln.DotSettings for custom code cleanup profiles. - Include configuration for formatting, reordering, and optimizing imports for various languages. - Ensure consistent code style across IDEs with shared settings. --- ...Craft.SourceGeneratorTools.sln.DotSettings | 137 ++++++++++++++++++ 1 file changed, 137 insertions(+) create mode 100644 LayeredCraft.SourceGeneratorTools.sln.DotSettings diff --git a/LayeredCraft.SourceGeneratorTools.sln.DotSettings b/LayeredCraft.SourceGeneratorTools.sln.DotSettings new file mode 100644 index 0000000..e872850 --- /dev/null +++ b/LayeredCraft.SourceGeneratorTools.sln.DotSettings @@ -0,0 +1,137 @@ + + <?xml version="1.0" encoding="utf-16"?><Profile name="Full Custom Cleanup"><CppReformatCode>True</CppReformatCode><FSharpReformatCode>True</FSharpReformatCode><ShaderLabReformatCode>True</ShaderLabReformatCode><XMLReformatCode>True</XMLReformatCode><VBReformatCode>True</VBReformatCode><CSReformatCode>True</CSReformatCode><CSharpReformatComments>True</CSharpReformatComments><CSCodeStyleAttributes ArrangeVarStyle="True" ArrangeTypeAccessModifier="True" ArrangeTypeMemberAccessModifier="True" SortModifiers="True" ArrangeArgumentsStyle="True" RemoveRedundantParentheses="True" AddMissingParentheses="True" ArrangeBraces="True" ArrangeAttributes="True" ArrangeCodeBodyStyle="True" ArrangeTrailingCommas="True" ArrangeObjectCreation="True" ArrangeDefaultValue="True" ArrangeNamespaces="True" ArrangeNullCheckingPattern="True" /><CSArrangeQualifiers>True</CSArrangeQualifiers><CSFixBuiltinTypeReferences>True</CSFixBuiltinTypeReferences><CppCodeStyleCleanupDescriptor ArrangeBraces="True" ArrangeAuto="True" ArrangeFunctionDeclarations="True" ArrangeNestedNamespaces="True" ArrangeTypeAliases="True" ArrangeCVQualifiers="True" ArrangeSlashesInIncludeDirectives="True" ArrangeOverridingFunctions="True" SortDefinitions="True" SortIncludeDirectives="True" SortMemberInitializers="True" /><FormatAttributeQuoteDescriptor>True</FormatAttributeQuoteDescriptor><CSOptimizeUsings><OptimizeUsings>True</OptimizeUsings></CSOptimizeUsings><CSShortenReferences>True</CSShortenReferences><VBOptimizeImports>True</VBOptimizeImports><VBShortenReferences>True</VBShortenReferences><Xaml.RemoveRedundantNamespaceAlias>True</Xaml.RemoveRedundantNamespaceAlias><AspOptimizeRegisterDirectives>True</AspOptimizeRegisterDirectives><CSReorderTypeMembers>True</CSReorderTypeMembers><RemoveCodeRedundancies>True</RemoveCodeRedundancies><CSUseAutoProperty>True</CSUseAutoProperty><CSMakeFieldReadonly>True</CSMakeFieldReadonly><CSMakeAutoPropertyGetOnly>True</CSMakeAutoPropertyGetOnly><CppAddTypenameTemplateKeywords>True</CppAddTypenameTemplateKeywords><CppCStyleToStaticCastDescriptor>True</CppCStyleToStaticCastDescriptor><CppRedundantDereferences>True</CppRedundantDereferences><CppDeleteRedundantAccessSpecifier>True</CppDeleteRedundantAccessSpecifier><CppRemoveCastDescriptor>True</CppRemoveCastDescriptor><CppRemoveElseKeyword>True</CppRemoveElseKeyword><CppShortenQualifiedName>True</CppShortenQualifiedName><CppDeleteRedundantSpecifier>True</CppDeleteRedundantSpecifier><CppRemoveStatement>True</CppRemoveStatement><CppDeleteRedundantTypenameTemplateKeywords>True</CppDeleteRedundantTypenameTemplateKeywords><CppReplaceExpressionWithBooleanConst>True</CppReplaceExpressionWithBooleanConst><CppMakeIfConstexpr>True</CppMakeIfConstexpr><CppMakePostfixOperatorPrefix>True</CppMakePostfixOperatorPrefix><CppMakeVariableConstexpr>True</CppMakeVariableConstexpr><CppChangeSmartPointerToMakeFunction>True</CppChangeSmartPointerToMakeFunction><CppReplaceThrowWithRethrowFix>True</CppReplaceThrowWithRethrowFix><CppTypeTraitAliasDescriptor>True</CppTypeTraitAliasDescriptor><CppRemoveRedundantConditionalExpressionDescriptor>True</CppRemoveRedundantConditionalExpressionDescriptor><CppSimplifyConditionalExpressionDescriptor>True</CppSimplifyConditionalExpressionDescriptor><CppReplaceExpressionWithNullptr>True</CppReplaceExpressionWithNullptr><CppReplaceTieWithStructuredBindingDescriptor>True</CppReplaceTieWithStructuredBindingDescriptor><CppUseAssociativeContainsDescriptor>True</CppUseAssociativeContainsDescriptor><CppUseEraseAlgorithmDescriptor>True</CppUseEraseAlgorithmDescriptor><CppJoinDeclarationAndAssignmentDescriptor>True</CppJoinDeclarationAndAssignmentDescriptor><CppMakeClassFinal>True</CppMakeClassFinal><CppMakeLocalVarConstDescriptor>True</CppMakeLocalVarConstDescriptor><CppMakeMethodConst>True</CppMakeMethodConst><CppMakeMethodStatic>True</CppMakeMethodStatic><CppMakePtrOrRefParameterConst>True</CppMakePtrOrRefParameterConst><CppMakeParameterConst>True</CppMakeParameterConst><CppPassValueParameterByConstReference>True</CppPassValueParameterByConstReference><CppRemoveElaboratedTypeSpecifierDescriptor>True</CppRemoveElaboratedTypeSpecifierDescriptor><CppRemoveRedundantLambdaParameterListDescriptor>True</CppRemoveRedundantLambdaParameterListDescriptor><CppRemoveRedundantMemberInitializerDescriptor>True</CppRemoveRedundantMemberInitializerDescriptor><CppRemoveRedundantParentheses>True</CppRemoveRedundantParentheses><CppRemoveTemplateArgumentsDescriptor>True</CppRemoveTemplateArgumentsDescriptor><CppRemoveUnreachableCode>True</CppRemoveUnreachableCode><CppRemoveUnusedIncludes>True</CppRemoveUnusedIncludes><CppRemoveUnusedLambdaCaptures>True</CppRemoveUnusedLambdaCaptures><CppReplaceIfWithIfConsteval>True</CppReplaceIfWithIfConsteval><RemoveCodeRedundanciesVB>True</RemoveCodeRedundanciesVB><VBMakeFieldReadonly>True</VBMakeFieldReadonly><Xaml.RedundantFreezeAttribute>True</Xaml.RedundantFreezeAttribute><Xaml.RemoveRedundantModifiersAttribute>True</Xaml.RemoveRedundantModifiersAttribute><Xaml.RemoveRedundantNameAttribute>True</Xaml.RemoveRedundantNameAttribute><Xaml.RemoveRedundantResource>True</Xaml.RemoveRedundantResource><Xaml.RemoveRedundantCollectionProperty>True</Xaml.RemoveRedundantCollectionProperty><Xaml.RemoveRedundantAttachedPropertySetter>True</Xaml.RemoveRedundantAttachedPropertySetter><Xaml.RemoveRedundantStyledValue>True</Xaml.RemoveRedundantStyledValue><Xaml.RemoveForbiddenResourceName>True</Xaml.RemoveForbiddenResourceName><Xaml.RemoveRedundantGridDefinitionsAttribute>True</Xaml.RemoveRedundantGridDefinitionsAttribute><Xaml.RemoveRedundantUpdateSourceTriggerAttribute>True</Xaml.RemoveRedundantUpdateSourceTriggerAttribute><Xaml.RemoveRedundantBindingModeAttribute>True</Xaml.RemoveRedundantBindingModeAttribute><Xaml.RemoveRedundantGridSpanAttribut>True</Xaml.RemoveRedundantGridSpanAttribut><IDEA_SETTINGS>&lt;profile version="1.0"&gt; + &lt;option name="myName" value="Full Custom Cleanup" /&gt; + &lt;inspection_tool class="ConditionalExpressionWithIdenticalBranchesJS" enabled="true" level="WARNING" enabled_by_default="true" /&gt; + &lt;inspection_tool class="ES6ShorthandObjectProperty" enabled="true" level="WARNING" enabled_by_default="true" /&gt; + &lt;inspection_tool class="JSArrowFunctionBracesCanBeRemoved" enabled="true" level="WARNING" enabled_by_default="true" /&gt; + &lt;inspection_tool class="JSRemoveUnnecessaryParentheses" enabled="true" level="WARNING" enabled_by_default="true" /&gt; + &lt;inspection_tool class="UnterminatedStatementJS" enabled="true" level="WARNING" enabled_by_default="true" /&gt; +&lt;/profile&gt;</IDEA_SETTINGS><RIDER_SETTINGS>&lt;profile&gt; + &lt;Language id="CSS"&gt; + &lt;Rearrange&gt;true&lt;/Rearrange&gt; + &lt;Reformat&gt;true&lt;/Reformat&gt; + &lt;/Language&gt; + &lt;Language id="EditorConfig"&gt; + &lt;Reformat&gt;true&lt;/Reformat&gt; + &lt;/Language&gt; + &lt;Language id="HCL"&gt; + &lt;Reformat&gt;true&lt;/Reformat&gt; + &lt;/Language&gt; + &lt;Language id="HTML"&gt; + &lt;OptimizeImports&gt;true&lt;/OptimizeImports&gt; + &lt;Rearrange&gt;true&lt;/Rearrange&gt; + &lt;Reformat&gt;true&lt;/Reformat&gt; + &lt;/Language&gt; + &lt;Language id="HTTP Request"&gt; + &lt;Reformat&gt;true&lt;/Reformat&gt; + &lt;/Language&gt; + &lt;Language id="Handlebars"&gt; + &lt;Reformat&gt;true&lt;/Reformat&gt; + &lt;/Language&gt; + &lt;Language id="Ini"&gt; + &lt;Reformat&gt;true&lt;/Reformat&gt; + &lt;/Language&gt; + &lt;Language id="JSON"&gt; + &lt;Reformat&gt;true&lt;/Reformat&gt; + &lt;/Language&gt; + &lt;Language id="Jade"&gt; + &lt;Reformat&gt;true&lt;/Reformat&gt; + &lt;/Language&gt; + &lt;Language id="JavaScript"&gt; + &lt;OptimizeImports&gt;true&lt;/OptimizeImports&gt; + &lt;Rearrange&gt;true&lt;/Rearrange&gt; + &lt;Reformat&gt;true&lt;/Reformat&gt; + &lt;/Language&gt; + &lt;Language id="Markdown"&gt; + &lt;Reformat&gt;false&lt;/Reformat&gt; + &lt;/Language&gt; + &lt;Language id="Mermaid"&gt; + &lt;Reformat&gt;true&lt;/Reformat&gt; + &lt;/Language&gt; + &lt;Language id="PowerShell"&gt; + &lt;Reformat&gt;true&lt;/Reformat&gt; + &lt;/Language&gt; + &lt;Language id="Properties"&gt; + &lt;Reformat&gt;true&lt;/Reformat&gt; + &lt;/Language&gt; + &lt;Language id="RELAX-NG"&gt; + &lt;Reformat&gt;true&lt;/Reformat&gt; + &lt;/Language&gt; + &lt;Language id="Razor"&gt; + &lt;Reformat&gt;true&lt;/Reformat&gt; + &lt;/Language&gt; + &lt;Language id="SQL"&gt; + &lt;Reformat&gt;true&lt;/Reformat&gt; + &lt;/Language&gt; + &lt;Language id="TOML"&gt; + &lt;Reformat&gt;true&lt;/Reformat&gt; + &lt;/Language&gt; + &lt;Language id="VueExpr"&gt; + &lt;Reformat&gt;true&lt;/Reformat&gt; + &lt;/Language&gt; + &lt;Language id="XML"&gt; + &lt;OptimizeImports&gt;true&lt;/OptimizeImports&gt; + &lt;Rearrange&gt;true&lt;/Rearrange&gt; + &lt;Reformat&gt;true&lt;/Reformat&gt; + &lt;/Language&gt; + &lt;Language id="yaml"&gt; + &lt;Reformat&gt;true&lt;/Reformat&gt; + &lt;/Language&gt; +&lt;/profile&gt;</RIDER_SETTINGS><CSharpFormatDocComments>True</CSharpFormatDocComments></Profile> + Built-in: Full Cleanup + NotRequired + NotRequired + NotRequired + NotRequired + ExpressionBody + ExpressionBody + ExpressionBody + True + False + False + False + False + False + False + False + True + 1 + ALWAYS + ALWAYS + ALWAYS + False + NEVER + False + False + ALWAYS_IF_MULTILINE + True + True + CHOP_IF_LONG + False + True + True + True + True + True + CHOP_IF_LONG + True + CHOP_IF_LONG + CHOP_IF_LONG + 2 + False + False + 2 + ByFirstAttr + True + False + True + False + False + True + False + False + True + True + True + True + True \ No newline at end of file From a25ded6d2500f1367068c54284bdf7f071eddb7c Mon Sep 17 00:00:00 2001 From: Jonas Ha Date: Sat, 20 Dec 2025 10:49:05 -0500 Subject: [PATCH 06/11] chore(project): add LayeredCraft.SourceGeneratorTools.Generator project - Introduce new .NET Standard 2.0 library project for source generator tools. - Enable nullable reference types and C# preview features. - Add dependencies for Microsoft.CodeAnalysis.CSharp and Microsoft.CodeAnalysis.Analyzers. - Include additional project metadata and non-code assets (e.g. icon, README). --- ...Craft.SourceGeneratorTools.Generator.csproj | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 src/LayeredCraft.SourceGeneratorTools.Generator/LayeredCraft.SourceGeneratorTools.Generator.csproj diff --git a/src/LayeredCraft.SourceGeneratorTools.Generator/LayeredCraft.SourceGeneratorTools.Generator.csproj b/src/LayeredCraft.SourceGeneratorTools.Generator/LayeredCraft.SourceGeneratorTools.Generator.csproj new file mode 100644 index 0000000..e3ce6a7 --- /dev/null +++ b/src/LayeredCraft.SourceGeneratorTools.Generator/LayeredCraft.SourceGeneratorTools.Generator.csproj @@ -0,0 +1,18 @@ + + + netstandard2.0 + preview + enable + Library + true + false + + + + + + + + + + From bbd3b0de6e2b0d621f20c520376f344b2d4a4acb Mon Sep 17 00:00:00 2001 From: Jonas Ha Date: Sat, 20 Dec 2025 10:51:23 -0500 Subject: [PATCH 07/11] chore(project): update project settings for Roslyn components - Add IsRoslynComponent property to enable Roslyn component features. - Enable EnforceExtendedAnalyzerRules for stricter analysis enforcement. --- .../LayeredCraft.SourceGeneratorTools.Generator.csproj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/LayeredCraft.SourceGeneratorTools.Generator/LayeredCraft.SourceGeneratorTools.Generator.csproj b/src/LayeredCraft.SourceGeneratorTools.Generator/LayeredCraft.SourceGeneratorTools.Generator.csproj index e3ce6a7..64be553 100644 --- a/src/LayeredCraft.SourceGeneratorTools.Generator/LayeredCraft.SourceGeneratorTools.Generator.csproj +++ b/src/LayeredCraft.SourceGeneratorTools.Generator/LayeredCraft.SourceGeneratorTools.Generator.csproj @@ -4,6 +4,8 @@ preview enable Library + true + true true false From 1d7a90a5ce6c29c018964db82bbb1d6398bd4e8d Mon Sep 17 00:00:00 2001 From: Jonas Ha Date: Sat, 20 Dec 2025 10:53:47 -0500 Subject: [PATCH 08/11] chore(examples): add basic example project for source generator - Introduce `LayeredCraft.SourceGeneratorTools.BasicExample` project. - Add a simple console application demonstrating "Hello, World!". - Update solution file to include the new example project. --- LayeredCraft.SourceGeneratorTools.slnx | 3 +++ ...eredCraft.SourceGeneratorTools.BasicExample.csproj | 11 +++++++++++ .../Program.cs | 3 +++ .../SourceGenerator.cs | 3 +++ 4 files changed, 20 insertions(+) create mode 100644 examples/LayeredCraft.SourceGeneratorTools.BasicExample/LayeredCraft.SourceGeneratorTools.BasicExample.csproj create mode 100644 examples/LayeredCraft.SourceGeneratorTools.BasicExample/Program.cs create mode 100644 src/LayeredCraft.SourceGeneratorTools.Generator/SourceGenerator.cs diff --git a/LayeredCraft.SourceGeneratorTools.slnx b/LayeredCraft.SourceGeneratorTools.slnx index 63cd750..61b75cb 100644 --- a/LayeredCraft.SourceGeneratorTools.slnx +++ b/LayeredCraft.SourceGeneratorTools.slnx @@ -1,4 +1,7 @@ + + + diff --git a/examples/LayeredCraft.SourceGeneratorTools.BasicExample/LayeredCraft.SourceGeneratorTools.BasicExample.csproj b/examples/LayeredCraft.SourceGeneratorTools.BasicExample/LayeredCraft.SourceGeneratorTools.BasicExample.csproj new file mode 100644 index 0000000..e42e8f2 --- /dev/null +++ b/examples/LayeredCraft.SourceGeneratorTools.BasicExample/LayeredCraft.SourceGeneratorTools.BasicExample.csproj @@ -0,0 +1,11 @@ + + + Exe + net10.0 + preview + enable + enable + true + true + + diff --git a/examples/LayeredCraft.SourceGeneratorTools.BasicExample/Program.cs b/examples/LayeredCraft.SourceGeneratorTools.BasicExample/Program.cs new file mode 100644 index 0000000..139ec4e --- /dev/null +++ b/examples/LayeredCraft.SourceGeneratorTools.BasicExample/Program.cs @@ -0,0 +1,3 @@ +// See https://aka.ms/new-console-template for more information + +Console.WriteLine("Hello, World!"); diff --git a/src/LayeredCraft.SourceGeneratorTools.Generator/SourceGenerator.cs b/src/LayeredCraft.SourceGeneratorTools.Generator/SourceGenerator.cs new file mode 100644 index 0000000..079a375 --- /dev/null +++ b/src/LayeredCraft.SourceGeneratorTools.Generator/SourceGenerator.cs @@ -0,0 +1,3 @@ +namespace LayeredCraft.SourceGeneratorTools.Generator; + +public class SourceGenerator { } From f55e2a582d45d760e7c26188396eade4023e29af Mon Sep 17 00:00:00 2001 From: Jonas Ha Date: Sat, 20 Dec 2025 12:49:01 -0500 Subject: [PATCH 09/11] refactor(core): remove custom HashCode implementation and replace usages - Delete `HashCode` custom implementation in `Types` directory. - Update `EquatableArray` to use utilities from `Utilities.HashCode`. - Adjust namespace and declaration references in related tests. - Include generated constants for streamlined code inclusion. - Incorporate PolySharp for additional utility support. --- Directory.Packages.props | 1 + ...Craft.SourceGeneratorTools.sln.DotSettings | 5 +- ...t.SourceGeneratorTools.BasicExample.csproj | 10 +- .../Program.cs | 3 + .../GeneratableFeature.cs | 3 + .../GeneratorConstants.cs | 33 ++++++ ...raft.SourceGeneratorTools.Generator.csproj | 18 +++ .../SourceGenerator.cs | 3 - .../SourceGeneratorToolsGenerator.cs | 104 ++++++++++++++++++ .../{ => EquatableArray}/EquatableArray.cs | 4 +- .../EquatableArrayExtensions.cs | 0 .../{Types => Utilities}/HashCode.cs | 4 +- .../Types/HashCodeTests.cs | 2 +- 13 files changed, 179 insertions(+), 11 deletions(-) create mode 100644 src/LayeredCraft.SourceGeneratorTools.Generator/GeneratableFeature.cs create mode 100644 src/LayeredCraft.SourceGeneratorTools.Generator/GeneratorConstants.cs delete mode 100644 src/LayeredCraft.SourceGeneratorTools.Generator/SourceGenerator.cs create mode 100644 src/LayeredCraft.SourceGeneratorTools.Generator/SourceGeneratorToolsGenerator.cs rename src/LayeredCraft.SourceGeneratorTools/Types/{ => EquatableArray}/EquatableArray.cs (96%) rename src/LayeredCraft.SourceGeneratorTools/Types/{ => EquatableArray}/EquatableArrayExtensions.cs (100%) rename src/LayeredCraft.SourceGeneratorTools/{Types => Utilities}/HashCode.cs (99%) diff --git a/Directory.Packages.props b/Directory.Packages.props index 0ddb11f..f552466 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -6,6 +6,7 @@ + diff --git a/LayeredCraft.SourceGeneratorTools.sln.DotSettings b/LayeredCraft.SourceGeneratorTools.sln.DotSettings index e872850..ea1af3d 100644 --- a/LayeredCraft.SourceGeneratorTools.sln.DotSettings +++ b/LayeredCraft.SourceGeneratorTools.sln.DotSettings @@ -1,5 +1,5 @@  - <?xml version="1.0" encoding="utf-16"?><Profile name="Full Custom Cleanup"><CppReformatCode>True</CppReformatCode><FSharpReformatCode>True</FSharpReformatCode><ShaderLabReformatCode>True</ShaderLabReformatCode><XMLReformatCode>True</XMLReformatCode><VBReformatCode>True</VBReformatCode><CSReformatCode>True</CSReformatCode><CSharpReformatComments>True</CSharpReformatComments><CSCodeStyleAttributes ArrangeVarStyle="True" ArrangeTypeAccessModifier="True" ArrangeTypeMemberAccessModifier="True" SortModifiers="True" ArrangeArgumentsStyle="True" RemoveRedundantParentheses="True" AddMissingParentheses="True" ArrangeBraces="True" ArrangeAttributes="True" ArrangeCodeBodyStyle="True" ArrangeTrailingCommas="True" ArrangeObjectCreation="True" ArrangeDefaultValue="True" ArrangeNamespaces="True" ArrangeNullCheckingPattern="True" /><CSArrangeQualifiers>True</CSArrangeQualifiers><CSFixBuiltinTypeReferences>True</CSFixBuiltinTypeReferences><CppCodeStyleCleanupDescriptor ArrangeBraces="True" ArrangeAuto="True" ArrangeFunctionDeclarations="True" ArrangeNestedNamespaces="True" ArrangeTypeAliases="True" ArrangeCVQualifiers="True" ArrangeSlashesInIncludeDirectives="True" ArrangeOverridingFunctions="True" SortDefinitions="True" SortIncludeDirectives="True" SortMemberInitializers="True" /><FormatAttributeQuoteDescriptor>True</FormatAttributeQuoteDescriptor><CSOptimizeUsings><OptimizeUsings>True</OptimizeUsings></CSOptimizeUsings><CSShortenReferences>True</CSShortenReferences><VBOptimizeImports>True</VBOptimizeImports><VBShortenReferences>True</VBShortenReferences><Xaml.RemoveRedundantNamespaceAlias>True</Xaml.RemoveRedundantNamespaceAlias><AspOptimizeRegisterDirectives>True</AspOptimizeRegisterDirectives><CSReorderTypeMembers>True</CSReorderTypeMembers><RemoveCodeRedundancies>True</RemoveCodeRedundancies><CSUseAutoProperty>True</CSUseAutoProperty><CSMakeFieldReadonly>True</CSMakeFieldReadonly><CSMakeAutoPropertyGetOnly>True</CSMakeAutoPropertyGetOnly><CppAddTypenameTemplateKeywords>True</CppAddTypenameTemplateKeywords><CppCStyleToStaticCastDescriptor>True</CppCStyleToStaticCastDescriptor><CppRedundantDereferences>True</CppRedundantDereferences><CppDeleteRedundantAccessSpecifier>True</CppDeleteRedundantAccessSpecifier><CppRemoveCastDescriptor>True</CppRemoveCastDescriptor><CppRemoveElseKeyword>True</CppRemoveElseKeyword><CppShortenQualifiedName>True</CppShortenQualifiedName><CppDeleteRedundantSpecifier>True</CppDeleteRedundantSpecifier><CppRemoveStatement>True</CppRemoveStatement><CppDeleteRedundantTypenameTemplateKeywords>True</CppDeleteRedundantTypenameTemplateKeywords><CppReplaceExpressionWithBooleanConst>True</CppReplaceExpressionWithBooleanConst><CppMakeIfConstexpr>True</CppMakeIfConstexpr><CppMakePostfixOperatorPrefix>True</CppMakePostfixOperatorPrefix><CppMakeVariableConstexpr>True</CppMakeVariableConstexpr><CppChangeSmartPointerToMakeFunction>True</CppChangeSmartPointerToMakeFunction><CppReplaceThrowWithRethrowFix>True</CppReplaceThrowWithRethrowFix><CppTypeTraitAliasDescriptor>True</CppTypeTraitAliasDescriptor><CppRemoveRedundantConditionalExpressionDescriptor>True</CppRemoveRedundantConditionalExpressionDescriptor><CppSimplifyConditionalExpressionDescriptor>True</CppSimplifyConditionalExpressionDescriptor><CppReplaceExpressionWithNullptr>True</CppReplaceExpressionWithNullptr><CppReplaceTieWithStructuredBindingDescriptor>True</CppReplaceTieWithStructuredBindingDescriptor><CppUseAssociativeContainsDescriptor>True</CppUseAssociativeContainsDescriptor><CppUseEraseAlgorithmDescriptor>True</CppUseEraseAlgorithmDescriptor><CppJoinDeclarationAndAssignmentDescriptor>True</CppJoinDeclarationAndAssignmentDescriptor><CppMakeClassFinal>True</CppMakeClassFinal><CppMakeLocalVarConstDescriptor>True</CppMakeLocalVarConstDescriptor><CppMakeMethodConst>True</CppMakeMethodConst><CppMakeMethodStatic>True</CppMakeMethodStatic><CppMakePtrOrRefParameterConst>True</CppMakePtrOrRefParameterConst><CppMakeParameterConst>True</CppMakeParameterConst><CppPassValueParameterByConstReference>True</CppPassValueParameterByConstReference><CppRemoveElaboratedTypeSpecifierDescriptor>True</CppRemoveElaboratedTypeSpecifierDescriptor><CppRemoveRedundantLambdaParameterListDescriptor>True</CppRemoveRedundantLambdaParameterListDescriptor><CppRemoveRedundantMemberInitializerDescriptor>True</CppRemoveRedundantMemberInitializerDescriptor><CppRemoveRedundantParentheses>True</CppRemoveRedundantParentheses><CppRemoveTemplateArgumentsDescriptor>True</CppRemoveTemplateArgumentsDescriptor><CppRemoveUnreachableCode>True</CppRemoveUnreachableCode><CppRemoveUnusedIncludes>True</CppRemoveUnusedIncludes><CppRemoveUnusedLambdaCaptures>True</CppRemoveUnusedLambdaCaptures><CppReplaceIfWithIfConsteval>True</CppReplaceIfWithIfConsteval><RemoveCodeRedundanciesVB>True</RemoveCodeRedundanciesVB><VBMakeFieldReadonly>True</VBMakeFieldReadonly><Xaml.RedundantFreezeAttribute>True</Xaml.RedundantFreezeAttribute><Xaml.RemoveRedundantModifiersAttribute>True</Xaml.RemoveRedundantModifiersAttribute><Xaml.RemoveRedundantNameAttribute>True</Xaml.RemoveRedundantNameAttribute><Xaml.RemoveRedundantResource>True</Xaml.RemoveRedundantResource><Xaml.RemoveRedundantCollectionProperty>True</Xaml.RemoveRedundantCollectionProperty><Xaml.RemoveRedundantAttachedPropertySetter>True</Xaml.RemoveRedundantAttachedPropertySetter><Xaml.RemoveRedundantStyledValue>True</Xaml.RemoveRedundantStyledValue><Xaml.RemoveForbiddenResourceName>True</Xaml.RemoveForbiddenResourceName><Xaml.RemoveRedundantGridDefinitionsAttribute>True</Xaml.RemoveRedundantGridDefinitionsAttribute><Xaml.RemoveRedundantUpdateSourceTriggerAttribute>True</Xaml.RemoveRedundantUpdateSourceTriggerAttribute><Xaml.RemoveRedundantBindingModeAttribute>True</Xaml.RemoveRedundantBindingModeAttribute><Xaml.RemoveRedundantGridSpanAttribut>True</Xaml.RemoveRedundantGridSpanAttribut><IDEA_SETTINGS>&lt;profile version="1.0"&gt; + <?xml version="1.0" encoding="utf-16"?><Profile name="Full Custom Cleanup"><CppReformatCode>True</CppReformatCode><FSharpReformatCode>True</FSharpReformatCode><ShaderLabReformatCode>True</ShaderLabReformatCode><XMLReformatCode>True</XMLReformatCode><VBReformatCode>True</VBReformatCode><CSReformatCode>True</CSReformatCode><CSharpReformatComments>True</CSharpReformatComments><CSCodeStyleAttributes ArrangeVarStyle="True" ArrangeTypeAccessModifier="True" ArrangeTypeMemberAccessModifier="True" SortModifiers="True" ArrangeArgumentsStyle="True" RemoveRedundantParentheses="True" AddMissingParentheses="True" ArrangeBraces="True" ArrangeAttributes="True" ArrangeCodeBodyStyle="True" ArrangeTrailingCommas="True" ArrangeObjectCreation="True" ArrangeDefaultValue="True" ArrangeNamespaces="True" ArrangeNullCheckingPattern="True" /><CSArrangeQualifiers>True</CSArrangeQualifiers><CSFixBuiltinTypeReferences>True</CSFixBuiltinTypeReferences><CppCodeStyleCleanupDescriptor ArrangeBraces="True" ArrangeAuto="True" ArrangeFunctionDeclarations="True" ArrangeNestedNamespaces="True" ArrangeTypeAliases="True" ArrangeCVQualifiers="True" ArrangeSlashesInIncludeDirectives="True" ArrangeOverridingFunctions="True" SortDefinitions="True" SortIncludeDirectives="True" SortMemberInitializers="True" /><FormatAttributeQuoteDescriptor>True</FormatAttributeQuoteDescriptor><CSOptimizeUsings><OptimizeUsings>True</OptimizeUsings></CSOptimizeUsings><VBOptimizeImports>True</VBOptimizeImports><VBShortenReferences>True</VBShortenReferences><Xaml.RemoveRedundantNamespaceAlias>True</Xaml.RemoveRedundantNamespaceAlias><AspOptimizeRegisterDirectives>True</AspOptimizeRegisterDirectives><CSReorderTypeMembers>True</CSReorderTypeMembers><CSUseAutoProperty>True</CSUseAutoProperty><CSMakeFieldReadonly>True</CSMakeFieldReadonly><CSMakeAutoPropertyGetOnly>True</CSMakeAutoPropertyGetOnly><CppAddTypenameTemplateKeywords>True</CppAddTypenameTemplateKeywords><CppCStyleToStaticCastDescriptor>True</CppCStyleToStaticCastDescriptor><CppRedundantDereferences>True</CppRedundantDereferences><CppDeleteRedundantAccessSpecifier>True</CppDeleteRedundantAccessSpecifier><CppRemoveCastDescriptor>True</CppRemoveCastDescriptor><CppRemoveElseKeyword>True</CppRemoveElseKeyword><CppShortenQualifiedName>True</CppShortenQualifiedName><CppDeleteRedundantSpecifier>True</CppDeleteRedundantSpecifier><CppRemoveStatement>True</CppRemoveStatement><CppDeleteRedundantTypenameTemplateKeywords>True</CppDeleteRedundantTypenameTemplateKeywords><CppReplaceExpressionWithBooleanConst>True</CppReplaceExpressionWithBooleanConst><CppMakeIfConstexpr>True</CppMakeIfConstexpr><CppMakePostfixOperatorPrefix>True</CppMakePostfixOperatorPrefix><CppMakeVariableConstexpr>True</CppMakeVariableConstexpr><CppChangeSmartPointerToMakeFunction>True</CppChangeSmartPointerToMakeFunction><CppReplaceThrowWithRethrowFix>True</CppReplaceThrowWithRethrowFix><CppTypeTraitAliasDescriptor>True</CppTypeTraitAliasDescriptor><CppRemoveRedundantConditionalExpressionDescriptor>True</CppRemoveRedundantConditionalExpressionDescriptor><CppSimplifyConditionalExpressionDescriptor>True</CppSimplifyConditionalExpressionDescriptor><CppReplaceExpressionWithNullptr>True</CppReplaceExpressionWithNullptr><CppReplaceTieWithStructuredBindingDescriptor>True</CppReplaceTieWithStructuredBindingDescriptor><CppUseAssociativeContainsDescriptor>True</CppUseAssociativeContainsDescriptor><CppUseEraseAlgorithmDescriptor>True</CppUseEraseAlgorithmDescriptor><CppJoinDeclarationAndAssignmentDescriptor>True</CppJoinDeclarationAndAssignmentDescriptor><CppMakeClassFinal>True</CppMakeClassFinal><CppMakeLocalVarConstDescriptor>True</CppMakeLocalVarConstDescriptor><CppMakeMethodConst>True</CppMakeMethodConst><CppMakeMethodStatic>True</CppMakeMethodStatic><CppMakePtrOrRefParameterConst>True</CppMakePtrOrRefParameterConst><CppMakeParameterConst>True</CppMakeParameterConst><CppPassValueParameterByConstReference>True</CppPassValueParameterByConstReference><CppRemoveElaboratedTypeSpecifierDescriptor>True</CppRemoveElaboratedTypeSpecifierDescriptor><CppRemoveRedundantLambdaParameterListDescriptor>True</CppRemoveRedundantLambdaParameterListDescriptor><CppRemoveRedundantMemberInitializerDescriptor>True</CppRemoveRedundantMemberInitializerDescriptor><CppRemoveRedundantParentheses>True</CppRemoveRedundantParentheses><CppRemoveTemplateArgumentsDescriptor>True</CppRemoveTemplateArgumentsDescriptor><CppRemoveUnreachableCode>True</CppRemoveUnreachableCode><CppRemoveUnusedIncludes>True</CppRemoveUnusedIncludes><CppRemoveUnusedLambdaCaptures>True</CppRemoveUnusedLambdaCaptures><CppReplaceIfWithIfConsteval>True</CppReplaceIfWithIfConsteval><RemoveCodeRedundanciesVB>True</RemoveCodeRedundanciesVB><VBMakeFieldReadonly>True</VBMakeFieldReadonly><Xaml.RedundantFreezeAttribute>True</Xaml.RedundantFreezeAttribute><Xaml.RemoveRedundantModifiersAttribute>True</Xaml.RemoveRedundantModifiersAttribute><Xaml.RemoveRedundantNameAttribute>True</Xaml.RemoveRedundantNameAttribute><Xaml.RemoveRedundantResource>True</Xaml.RemoveRedundantResource><Xaml.RemoveRedundantCollectionProperty>True</Xaml.RemoveRedundantCollectionProperty><Xaml.RemoveRedundantAttachedPropertySetter>True</Xaml.RemoveRedundantAttachedPropertySetter><Xaml.RemoveRedundantStyledValue>True</Xaml.RemoveRedundantStyledValue><Xaml.RemoveForbiddenResourceName>True</Xaml.RemoveForbiddenResourceName><Xaml.RemoveRedundantGridDefinitionsAttribute>True</Xaml.RemoveRedundantGridDefinitionsAttribute><Xaml.RemoveRedundantUpdateSourceTriggerAttribute>True</Xaml.RemoveRedundantUpdateSourceTriggerAttribute><Xaml.RemoveRedundantBindingModeAttribute>True</Xaml.RemoveRedundantBindingModeAttribute><Xaml.RemoveRedundantGridSpanAttribut>True</Xaml.RemoveRedundantGridSpanAttribut><IDEA_SETTINGS>&lt;profile version="1.0"&gt; &lt;option name="myName" value="Full Custom Cleanup" /&gt; &lt;inspection_tool class="ConditionalExpressionWithIdenticalBranchesJS" enabled="true" level="WARNING" enabled_by_default="true" /&gt; &lt;inspection_tool class="ES6ShorthandObjectProperty" enabled="true" level="WARNING" enabled_by_default="true" /&gt; @@ -77,7 +77,7 @@ &lt;Language id="yaml"&gt; &lt;Reformat&gt;true&lt;/Reformat&gt; &lt;/Language&gt; -&lt;/profile&gt;</RIDER_SETTINGS><CSharpFormatDocComments>True</CSharpFormatDocComments></Profile> +&lt;/profile&gt;</RIDER_SETTINGS><CSharpFormatDocComments>True</CSharpFormatDocComments><RemoveCodeRedundancies>True</RemoveCodeRedundancies></Profile> Built-in: Full Cleanup NotRequired NotRequired @@ -124,6 +124,7 @@ ByFirstAttr True False + False True False False diff --git a/examples/LayeredCraft.SourceGeneratorTools.BasicExample/LayeredCraft.SourceGeneratorTools.BasicExample.csproj b/examples/LayeredCraft.SourceGeneratorTools.BasicExample/LayeredCraft.SourceGeneratorTools.BasicExample.csproj index e42e8f2..69590d4 100644 --- a/examples/LayeredCraft.SourceGeneratorTools.BasicExample/LayeredCraft.SourceGeneratorTools.BasicExample.csproj +++ b/examples/LayeredCraft.SourceGeneratorTools.BasicExample/LayeredCraft.SourceGeneratorTools.BasicExample.csproj @@ -5,7 +5,13 @@ preview enable enable - true - true + false + + + diff --git a/examples/LayeredCraft.SourceGeneratorTools.BasicExample/Program.cs b/examples/LayeredCraft.SourceGeneratorTools.BasicExample/Program.cs index 139ec4e..2924520 100644 --- a/examples/LayeredCraft.SourceGeneratorTools.BasicExample/Program.cs +++ b/examples/LayeredCraft.SourceGeneratorTools.BasicExample/Program.cs @@ -1,3 +1,6 @@ // See https://aka.ms/new-console-template for more information +using LayeredCraft.SourceGeneratorTools.Types; + Console.WriteLine("Hello, World!"); +new EquatableArray(); diff --git a/src/LayeredCraft.SourceGeneratorTools.Generator/GeneratableFeature.cs b/src/LayeredCraft.SourceGeneratorTools.Generator/GeneratableFeature.cs new file mode 100644 index 0000000..5fb8897 --- /dev/null +++ b/src/LayeredCraft.SourceGeneratorTools.Generator/GeneratableFeature.cs @@ -0,0 +1,3 @@ +namespace LayeredCraft.SourceGeneratorTools.Generator; + +internal readonly record struct GeneratableFeature(string Name, string[] FolderPaths); diff --git a/src/LayeredCraft.SourceGeneratorTools.Generator/GeneratorConstants.cs b/src/LayeredCraft.SourceGeneratorTools.Generator/GeneratorConstants.cs new file mode 100644 index 0000000..e2d09b1 --- /dev/null +++ b/src/LayeredCraft.SourceGeneratorTools.Generator/GeneratorConstants.cs @@ -0,0 +1,33 @@ +using System.Collections.Generic; + +namespace LayeredCraft.SourceGeneratorTools.Generator; + +internal static class GeneratorConstants +{ + internal const string GeneratedCodeHeader = """ + //------------------------------------------------------------------------------ + // + // This code was generated by a tool. + // + // Changes to this file may cause incorrect behavior and will be lost if + // the code is regenerated. + // + //------------------------------------------------------------------------------ + + #nullable enable + + + """; + + internal static readonly Dictionary Features = new() + { + ["EquatableArray"] = new GeneratableFeature( + "EquatableArray", + [ + "Tools/Types/EquatableArray/EquatableArray.cs", + "Tools/Types/EquatableArray/EquatableArrayExtensions.cs", + "Tools/Utilities/HashCode.cs", + ] + ), + }; +} diff --git a/src/LayeredCraft.SourceGeneratorTools.Generator/LayeredCraft.SourceGeneratorTools.Generator.csproj b/src/LayeredCraft.SourceGeneratorTools.Generator/LayeredCraft.SourceGeneratorTools.Generator.csproj index 64be553..964c7d0 100644 --- a/src/LayeredCraft.SourceGeneratorTools.Generator/LayeredCraft.SourceGeneratorTools.Generator.csproj +++ b/src/LayeredCraft.SourceGeneratorTools.Generator/LayeredCraft.SourceGeneratorTools.Generator.csproj @@ -12,9 +12,27 @@ + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + Tools\%(RecursiveDir)%(Filename)%(Extension) + + + + + System.Runtime.CompilerServices.ModuleInitializerAttribute + diff --git a/src/LayeredCraft.SourceGeneratorTools.Generator/SourceGenerator.cs b/src/LayeredCraft.SourceGeneratorTools.Generator/SourceGenerator.cs deleted file mode 100644 index 079a375..0000000 --- a/src/LayeredCraft.SourceGeneratorTools.Generator/SourceGenerator.cs +++ /dev/null @@ -1,3 +0,0 @@ -namespace LayeredCraft.SourceGeneratorTools.Generator; - -public class SourceGenerator { } diff --git a/src/LayeredCraft.SourceGeneratorTools.Generator/SourceGeneratorToolsGenerator.cs b/src/LayeredCraft.SourceGeneratorTools.Generator/SourceGeneratorToolsGenerator.cs new file mode 100644 index 0000000..547af93 --- /dev/null +++ b/src/LayeredCraft.SourceGeneratorTools.Generator/SourceGeneratorToolsGenerator.cs @@ -0,0 +1,104 @@ +using System.IO; +using Microsoft.CodeAnalysis; + +namespace LayeredCraft.SourceGeneratorTools.Generator; + +[Generator] +public class SourceGeneratorToolsGenerator : IIncrementalGenerator +{ + public void Initialize(IncrementalGeneratorInitializationContext context) + { + context.RegisterPostInitializationOutput(ctx => + { + // For now, hardcode to EquatableArray - in the future this could be configurable + var featureKeys = new[] { "EquatableArray" }; + + var assembly = typeof(SourceGeneratorToolsGenerator).Assembly; + + foreach (var featureKey in featureKeys) + { + if (!GeneratorConstants.Features.TryGetValue(featureKey, out var feature)) + continue; + + // Get the assembly namespace for resource lookup + var assemblyNamespace = assembly.GetName().Name; + + // Load each file path specified in the feature + foreach (var filePath in feature.FolderPaths) + { + // Convert file path to embedded resource name (add assembly namespace and + // replace / with .) + var resourceName = $"{assemblyNamespace}.{filePath.Replace('/', '.')}"; + + using var stream = assembly.GetManifestResourceStream(resourceName); + if (stream == null) + continue; + + using var reader = new StreamReader(stream); + var content = reader.ReadToEnd(); + + // Extract filename from the path + var fileName = Path.GetFileName(filePath); + var generatedFileName = Path.GetFileNameWithoutExtension(fileName) + ".g.cs"; + + var source = GeneratorConstants.GeneratedCodeHeader + content; + + ctx.AddSource(generatedFileName, source); + } + } + }); + + // Process additional files marked for source generation + var filesToGenerate = context + .AdditionalTextsProvider.Combine(context.AnalyzerConfigOptionsProvider) + .Where(pair => + { + var (file, options) = pair; + options + .GetOptions(file) + .TryGetValue( + "build_metadata.AdditionalFiles.SourceGenerate", + out var shouldGenerate + ); + return shouldGenerate == "true"; + }) + .Select( + (pair, cancellationToken) => + { + var (file, options) = pair; + var content = file.GetText(cancellationToken)?.ToString() ?? string.Empty; + var fileName = Path.GetFileName(file.Path); + + // Get optional output path override + options + .GetOptions(file) + .TryGetValue( + "build_metadata.AdditionalFiles.OutputPath", + out var outputPath + ); + + return (FileName: fileName, Content: content, OutputPath: outputPath); + } + ); + + context.RegisterSourceOutput( + filesToGenerate, + (ctx, file) => + { + // Use OutputPath if specified, otherwise use the original filename with .g.cs + // extension + var generatedFileName = !string.IsNullOrEmpty(file.OutputPath) + ? file.OutputPath + : Path.GetFileNameWithoutExtension(file.FileName) + ".g.cs"; + + // Ensure we have a valid filename + if (string.IsNullOrWhiteSpace(generatedFileName)) + return; + + var source = GeneratorConstants.GeneratedCodeHeader + file.Content; + + ctx.AddSource(generatedFileName!, source); + } + ); + } +} diff --git a/src/LayeredCraft.SourceGeneratorTools/Types/EquatableArray.cs b/src/LayeredCraft.SourceGeneratorTools/Types/EquatableArray/EquatableArray.cs similarity index 96% rename from src/LayeredCraft.SourceGeneratorTools/Types/EquatableArray.cs rename to src/LayeredCraft.SourceGeneratorTools/Types/EquatableArray/EquatableArray.cs index 0ab266a..08ee32e 100644 --- a/src/LayeredCraft.SourceGeneratorTools/Types/EquatableArray.cs +++ b/src/LayeredCraft.SourceGeneratorTools/Types/EquatableArray/EquatableArray.cs @@ -6,6 +6,8 @@ using System.Collections.Generic; using System.Collections.Immutable; +// ReSharper disable RedundantNameQualifier + namespace LayeredCraft.SourceGeneratorTools.Types; /// @@ -37,7 +39,7 @@ public override int GetHashCode() if (_array is not T[] array) return 0; - HashCode hashCode = default; + LayeredCraft.SourceGeneratorTools.Utilities.HashCode hashCode = default; foreach (var item in array) hashCode.Add(item); diff --git a/src/LayeredCraft.SourceGeneratorTools/Types/EquatableArrayExtensions.cs b/src/LayeredCraft.SourceGeneratorTools/Types/EquatableArray/EquatableArrayExtensions.cs similarity index 100% rename from src/LayeredCraft.SourceGeneratorTools/Types/EquatableArrayExtensions.cs rename to src/LayeredCraft.SourceGeneratorTools/Types/EquatableArray/EquatableArrayExtensions.cs diff --git a/src/LayeredCraft.SourceGeneratorTools/Types/HashCode.cs b/src/LayeredCraft.SourceGeneratorTools/Utilities/HashCode.cs similarity index 99% rename from src/LayeredCraft.SourceGeneratorTools/Types/HashCode.cs rename to src/LayeredCraft.SourceGeneratorTools/Utilities/HashCode.cs index 4ec9b86..d6b50ac 100644 --- a/src/LayeredCraft.SourceGeneratorTools/Types/HashCode.cs +++ b/src/LayeredCraft.SourceGeneratorTools/Utilities/HashCode.cs @@ -3,10 +3,10 @@ using System.ComponentModel; using System.Runtime.CompilerServices; -namespace LayeredCraft.SourceGeneratorTools.Types; +namespace LayeredCraft.SourceGeneratorTools.Utilities; /// Polyfill for .NET 6 HashCode -internal struct HashCode +public struct HashCode { private static readonly uint s_seed = GenerateGlobalSeed(); diff --git a/test/LayeredCraft.SourceGeneratorTools.UnitTests/Types/HashCodeTests.cs b/test/LayeredCraft.SourceGeneratorTools.UnitTests/Types/HashCodeTests.cs index 4eebe00..c5f291c 100644 --- a/test/LayeredCraft.SourceGeneratorTools.UnitTests/Types/HashCodeTests.cs +++ b/test/LayeredCraft.SourceGeneratorTools.UnitTests/Types/HashCodeTests.cs @@ -1,6 +1,6 @@ using AwesomeAssertions; using JetBrains.Annotations; -using HashCode = LayeredCraft.SourceGeneratorTools.Types.HashCode; +using HashCode = LayeredCraft.SourceGeneratorTools.Utilities.HashCode; namespace LayeredCraft.SourceGeneratorTools.UnitTests.Types; From eb9a3f5948206235fb6b207d506463fe540ecbd7 Mon Sep 17 00:00:00 2001 From: Jonas Ha Date: Sat, 20 Dec 2025 14:33:41 -0500 Subject: [PATCH 10/11] refactor(generator): optimize public modifier handling in source generation - Add `ConvertPublicToInternal` method to streamline "public" to "internal" modification. - Introduce constants for modifiers and a skip comment to improve readability. - Replace `StreamReader` implementation for efficiency and reuse. - Remove unused additional file processing logic for code simplification. --- .../SourceGeneratorToolsGenerator.cs | 84 +++++++------------ 1 file changed, 28 insertions(+), 56 deletions(-) diff --git a/src/LayeredCraft.SourceGeneratorTools.Generator/SourceGeneratorToolsGenerator.cs b/src/LayeredCraft.SourceGeneratorTools.Generator/SourceGeneratorToolsGenerator.cs index 547af93..eaa1bb4 100644 --- a/src/LayeredCraft.SourceGeneratorTools.Generator/SourceGeneratorToolsGenerator.cs +++ b/src/LayeredCraft.SourceGeneratorTools.Generator/SourceGeneratorToolsGenerator.cs @@ -1,4 +1,6 @@ +using System; using System.IO; +using System.Text; using Microsoft.CodeAnalysis; namespace LayeredCraft.SourceGeneratorTools.Generator; @@ -6,8 +8,12 @@ namespace LayeredCraft.SourceGeneratorTools.Generator; [Generator] public class SourceGeneratorToolsGenerator : IIncrementalGenerator { - public void Initialize(IncrementalGeneratorInitializationContext context) - { + private const string PublicModifier = "public"; + private const string InternalModifier = "internal"; + private const string NoReplaceComment = "// no-replace"; + private const int PublicModifierLength = 6; + + public void Initialize(IncrementalGeneratorInitializationContext context) => context.RegisterPostInitializationOutput(ctx => { // For now, hardcode to EquatableArray - in the future this could be configurable @@ -34,8 +40,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context) if (stream == null) continue; - using var reader = new StreamReader(stream); - var content = reader.ReadToEnd(); + var content = ConvertPublicToInternal(stream); // Extract filename from the path var fileName = Path.GetFileName(filePath); @@ -48,57 +53,24 @@ public void Initialize(IncrementalGeneratorInitializationContext context) } }); - // Process additional files marked for source generation - var filesToGenerate = context - .AdditionalTextsProvider.Combine(context.AnalyzerConfigOptionsProvider) - .Where(pair => - { - var (file, options) = pair; - options - .GetOptions(file) - .TryGetValue( - "build_metadata.AdditionalFiles.SourceGenerate", - out var shouldGenerate - ); - return shouldGenerate == "true"; - }) - .Select( - (pair, cancellationToken) => - { - var (file, options) = pair; - var content = file.GetText(cancellationToken)?.ToString() ?? string.Empty; - var fileName = Path.GetFileName(file.Path); - - // Get optional output path override - options - .GetOptions(file) - .TryGetValue( - "build_metadata.AdditionalFiles.OutputPath", - out var outputPath - ); - - return (FileName: fileName, Content: content, OutputPath: outputPath); - } - ); - - context.RegisterSourceOutput( - filesToGenerate, - (ctx, file) => - { - // Use OutputPath if specified, otherwise use the original filename with .g.cs - // extension - var generatedFileName = !string.IsNullOrEmpty(file.OutputPath) - ? file.OutputPath - : Path.GetFileNameWithoutExtension(file.FileName) + ".g.cs"; - - // Ensure we have a valid filename - if (string.IsNullOrWhiteSpace(generatedFileName)) - return; - - var source = GeneratorConstants.GeneratedCodeHeader + file.Content; - - ctx.AddSource(generatedFileName!, source); - } - ); + /// + /// Sets any line that starts with "public" to be "internal". This only impacts top-level + /// statements. This behavior can be skipped by adding a "// no-replace" at the end of the line. + /// + private static string ConvertPublicToInternal(Stream stream) + { + var sb = new StringBuilder((int)stream.Length); + using var reader = new StreamReader(stream); + + while (reader.ReadLine() is { } line) + if ( + line.StartsWith(PublicModifier) + && !line.Contains(NoReplaceComment, StringComparison.Ordinal) + ) + sb.Append(InternalModifier).AppendLine(line[PublicModifierLength..]); + else + sb.AppendLine(line); + + return sb.ToString(); } } From 23e1f0fe8897d71f4265a01a78b546b6e8111272 Mon Sep 17 00:00:00 2001 From: Jonas Ha Date: Sat, 20 Dec 2025 14:38:48 -0500 Subject: [PATCH 11/11] feat(project): enhance NuGet packaging metadata and configuration - Add `PackageId` and `Description` to .csproj files for NuGet packaging. - Include output assembly as an analyzer with appropriate paths and visibility settings. - Update `Directory.Build.props` with additional metadata like `PackageIcon`. - Adjust `PackageTags` for consistency in NuGet listings. --- Directory.Build.props | 3 ++- .../LayeredCraft.SourceGeneratorTools.Generator.csproj | 10 ++++++++++ .../LayeredCraft.SourceGeneratorTools.csproj | 2 ++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index 30af134..1fc3423 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -5,7 +5,7 @@ MIT Jonas Ha - csharp;library;utility;source generator + csharp;library;utility;SourceGenerator https://github.com/LayeredCraft/source-generator-tools Copyright © 2025 Jonas Ha https://github.com/LayeredCraft/source-generator-tools @@ -25,5 +25,6 @@ README.md + icon.png diff --git a/src/LayeredCraft.SourceGeneratorTools.Generator/LayeredCraft.SourceGeneratorTools.Generator.csproj b/src/LayeredCraft.SourceGeneratorTools.Generator/LayeredCraft.SourceGeneratorTools.Generator.csproj index 964c7d0..e37c386 100644 --- a/src/LayeredCraft.SourceGeneratorTools.Generator/LayeredCraft.SourceGeneratorTools.Generator.csproj +++ b/src/LayeredCraft.SourceGeneratorTools.Generator/LayeredCraft.SourceGeneratorTools.Generator.csproj @@ -8,6 +8,8 @@ true true false + LayeredCraft.SourceGeneratorTools.Generator + A generator to create a collection of helpers and tools for working with source generators @@ -35,4 +37,12 @@ System.Runtime.CompilerServices.ModuleInitializerAttribute + + + diff --git a/src/LayeredCraft.SourceGeneratorTools/LayeredCraft.SourceGeneratorTools.csproj b/src/LayeredCraft.SourceGeneratorTools/LayeredCraft.SourceGeneratorTools.csproj index 0fb88a3..b36d1ee 100644 --- a/src/LayeredCraft.SourceGeneratorTools/LayeredCraft.SourceGeneratorTools.csproj +++ b/src/LayeredCraft.SourceGeneratorTools/LayeredCraft.SourceGeneratorTools.csproj @@ -4,6 +4,8 @@ preview enable Library + LayeredCraft.SourceGeneratorTools + A collection of helpers and tools for working with source generators