Skip to content

feat: initial implementation of LayeredCraft.OptimizedEnums#1

Merged
ncipollina merged 7 commits into
mainfrom
feat/initial-implementation
Mar 30, 2026
Merged

feat: initial implementation of LayeredCraft.OptimizedEnums#1
ncipollina merged 7 commits into
mainfrom
feat/initial-implementation

Conversation

@ncipollina
Copy link
Copy Markdown
Contributor

Summary

Introduces the complete LayeredCraft.OptimizedEnums library — an AOT-safe, trim-friendly alternative to reflection-based smart enum patterns. The generator triggers on inheritance from OptimizedEnum<TEnum, TValue> (or the int-defaulting OptimizedEnum<TEnum> convenience class) rather than requiring an attribute, eliminating boilerplate and false positives on unrelated classes.

Changes

Runtime (src/LayeredCraft.OptimizedEnums)

  • OptimizedEnum<TEnum, TValue> — abstract base class with IEquatable<TEnum>, IComparable<TEnum>, value/name properties, operators
  • OptimizedEnum<TEnum> — single-parameter convenience class that fixes TValue = int

Source Generator (src/LayeredCraft.OptimizedEnums.Generator)

  • IIncrementalGenerator using CreateSyntaxProvider — inheritance-based triggering, no attribute needed
  • Base-type check happens first in Transform to avoid false diagnostics on unrelated types
  • Generates All, Names, Values, Count, FromName, TryFromName, FromValue, TryFromValue, ContainsName, ContainsValue
  • Diagnostics: OE0001 (not partial), OE0004 (no members), OE0005 (duplicate values), OE0006 (duplicate names), OE0101 (non-private ctor warning), OE0102 (non-readonly field warning)
  • Microsoft.CSharp.dll bundled in analyzers/dotnet/cs/ via GetDependencyTargetPaths MSBuild target so Scriban dynamic dispatch works in consuming packages

Tests

  • Runtime tests covering all generated members, equality, comparison, and error cases
  • Snapshot tests (Verify.SourceGenerators) covering happy paths and all diagnostic codes across net8.0 / net9.0 / net10.0
  • BenchmarkDotNet benchmarks comparing generated lookups vs. Enum.Parse / Enum.TryParse

Docs & CI

  • Full MkDocs Material documentation site (docs/, mkdocs.yml, requirements.txt)
  • GitHub Actions: build.yaml (push/tag), pr-build.yaml (PR validation), docs.yml (GitHub Pages deploy)
  • Dependabot for weekly NuGet updates

Validation

  • All runtime tests pass (net8.0 / net9.0 / net10.0)
  • All 21 generator snapshot tests pass across 3 frameworks
  • Benchmarks run cleanly in Release mode
  • Generator verified working end-to-end from a consumed NuGet package (including Microsoft.CSharp.dll bundling fix)
  • False-positive OE0001 on unrelated classes (e.g. Enumeration, domain events) confirmed resolved

Release Notes

Initial pre-release of LayeredCraft.OptimizedEnums. Inherit from OptimizedEnum<TEnum> (int-valued) or OptimizedEnum<TEnum, TValue> (custom value type) and the source generator emits O(1) lookup tables, collection properties, and factory methods — all AOT- and trim-safe with no reflection at runtime.

Introduces the full library: AOT-safe smart enum base classes, an
incremental source generator (inheritance-based triggering, no attribute
required), snapshot-tested generator suite, BenchmarkDotNet benchmarks,
MkDocs documentation site, and GitHub Actions CI/CD workflows.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 461cf905c3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/LayeredCraft.OptimizedEnums.Generator/Emitters/EnumEmitter.cs Outdated
ncipollina and others added 2 commits March 30, 2026 14:34
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- EnumEmitter: use fully-qualified name (minus global::) as hint name to
  prevent DuplicateHintNameException when two types share a class name
  across different namespaces
- EnumSyntaxProvider: capture containing type chain via
  GetContainingTypeDeclarations, stored as EquatableArray<string> on EnumInfo
- EnumEmitter: build preamble/suffix strings in C# instead of Scriban to
  avoid whitespace control complexity; nested types now emit correct
  partial class wrappers in the generated output
- Scriban template: replace namespace if-block with {{ preamble ~}} and
  add {{ suffix }} for containing type closing braces
- Rename snapshots to reflect new namespace-qualified hint names
- Add NestedType and SameClassName_DifferentNamespaces snapshot tests

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@ncipollina
Copy link
Copy Markdown
Contributor Author

@codex review

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5ff6210893

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/LayeredCraft.OptimizedEnums.Generator/Providers/EnumSyntaxProvider.cs Outdated
Comment thread src/LayeredCraft.OptimizedEnums.Generator/Providers/EnumSyntaxProvider.cs Outdated
Comment thread src/LayeredCraft.OptimizedEnums.Generator/Providers/EnumSyntaxProvider.cs Outdated
… coverage

- DiagnosticInfo.Equals/GetHashCode now include MessageArgs for correct incremental cache invalidation
- Add OE9001 GeneratorInternalError descriptor; wrap template render+AddSource in try/catch
- Replace C# 13 field keyword lazy prop with static readonly for thread safety in EnumEmitter
- Use HashSet<string> in DetectDuplicateValues to avoid O(n) Contains on validMembers list
- ReadOnlyCollection<T> via Array.AsReadOnly prevents cast-and-mutate of singleton collections
- Dictionary initial capacity hints and public const Count (compile-time constant) in template
- Add document Location exclusion comment in EnumInfo equality
- Add OE0101 assert, OE0102 non-readonly field, and OE0005 duplicate value tests (12 total, all pass)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Initial implementation of LayeredCraft.OptimizedEnums: a runtime base type plus an incremental source generator that emits lookup tables/APIs for “smart-enum” style classes, along with tests, benchmarks, docs, and CI wiring.

Changes:

  • Added runtime base classes (OptimizedEnum<TEnum, TValue> + OptimizedEnum<TEnum>) targeting netstandard2.0.
  • Added incremental source generator + Scriban template to emit cached collections and O(1) lookup APIs, with diagnostics.
  • Added xUnit runtime tests, generator snapshot tests (Verify), BenchmarkDotNet benchmarks, and MkDocs-based documentation + GitHub Actions/Dependabot.

Reviewed changes

Copilot reviewed 68 out of 74 changed files in this pull request and generated 14 comments.

Show a summary per file
File Description
tests/LayeredCraft.OptimizedEnums.Tests/xunit.runner.json xUnit runner schema config for runtime tests
tests/LayeredCraft.OptimizedEnums.Tests/OrderStatusFixture.cs Sample optimized-enum type used by runtime tests
tests/LayeredCraft.OptimizedEnums.Tests/OptimizedEnumTests.cs Runtime tests validating generated APIs + base behavior
tests/LayeredCraft.OptimizedEnums.Tests/LayeredCraft.OptimizedEnums.Tests.csproj Runtime test project wiring (mtp runner + generator as analyzer)
tests/LayeredCraft.OptimizedEnums.Generator.Tests/xunit.runner.json xUnit runner schema config for generator tests
tests/LayeredCraft.OptimizedEnums.Generator.Tests/ModuleInitializer.cs Verify.SourceGenerators initialization
tests/LayeredCraft.OptimizedEnums.Generator.Tests/LayeredCraft.OptimizedEnums.Generator.Tests.csproj Generator test project wiring + reference assemblies
tests/LayeredCraft.OptimizedEnums.Generator.Tests/GeneratorVerifyTests.cs Snapshot-style verification coverage for generator output/diagnostics
tests/LayeredCraft.OptimizedEnums.Generator.Tests/GeneratorTestHelpers.cs Roslyn compilation/driver harness for generator tests
tests/LayeredCraft.OptimizedEnums.Generator.Tests/Snapshots/GeneratorVerifyTests.Warning_NonPrivateConstructor#MyApp.Domain.OrderStatus.g.verified.cs Snapshot: generated output (warning scenario)
tests/LayeredCraft.OptimizedEnums.Generator.Tests/Snapshots/GeneratorVerifyTests.StringValueType#MyApp.Domain.Color.g.verified.cs Snapshot: generated output for string value type
tests/LayeredCraft.OptimizedEnums.Generator.Tests/Snapshots/GeneratorVerifyTests.SimpleEnum_WithNamespace#MyApp.Domain.OrderStatus.g.verified.cs Snapshot: generated output for namespaced enum
tests/LayeredCraft.OptimizedEnums.Generator.Tests/Snapshots/GeneratorVerifyTests.SimpleEnum_GlobalNamespace#Priority.g.verified.cs Snapshot: generated output for global-namespace enum
tests/LayeredCraft.OptimizedEnums.Generator.Tests/Snapshots/GeneratorVerifyTests.SameClassName_DifferentNamespaces#MyApp.Domain2.Status.g.verified.cs Snapshot: hint-name collision avoidance across namespaces
tests/LayeredCraft.OptimizedEnums.Generator.Tests/Snapshots/GeneratorVerifyTests.SameClassName_DifferentNamespaces#MyApp.Domain1.Status.g.verified.cs Snapshot: hint-name collision avoidance across namespaces
tests/LayeredCraft.OptimizedEnums.Generator.Tests/Snapshots/GeneratorVerifyTests.NestedType#MyApp.Domain.Outer.Status.g.verified.cs Snapshot: nested type generation behavior
tests/LayeredCraft.OptimizedEnums.Generator.Tests/Snapshots/GeneratorVerifyTests.MultipleMembers#MyApp.Domain.DayOfWeek.g.verified.cs Snapshot: multiple member generation behavior
tests/LayeredCraft.OptimizedEnums.Generator.Tests/Snapshots/GeneratorVerifyTests.Error_NotPartial.verified.txt Snapshot: OE0001 diagnostic output
tests/LayeredCraft.OptimizedEnums.Generator.Tests/Snapshots/GeneratorVerifyTests.Error_NoMembers.verified.txt Snapshot: OE0004 diagnostic output
tests/LayeredCraft.OptimizedEnums.Benchmarks/Program.cs BenchmarkDotNet entry point
tests/LayeredCraft.OptimizedEnums.Benchmarks/LayeredCraft.OptimizedEnums.Benchmarks.csproj Benchmarks project wiring + generator as analyzer
tests/LayeredCraft.OptimizedEnums.Benchmarks/EnumLookupBenchmarks.cs Benchmarks comparing generated lookups
tests/LayeredCraft.OptimizedEnums.Benchmarks/Directory.Build.props Overrides test global-usings for benchmarks project
tests/Directory.Build.props Global usings for test projects (Xunit, AwesomeAssertions)
src/LayeredCraft.OptimizedEnums/OptimizedEnum.cs Runtime base classes + equality/compare/operators
src/LayeredCraft.OptimizedEnums/LayeredCraft.OptimizedEnums.csproj Runtime project configuration (netstandard2.0)
src/LayeredCraft.OptimizedEnums.Generator/TrackingNames.cs Tracking names for incremental pipeline
src/LayeredCraft.OptimizedEnums.Generator/Templates/OptimizedEnum.scriban Scriban template for generated partial class
src/LayeredCraft.OptimizedEnums.Generator/Providers/EnumSyntaxProvider.cs Discovery/validation of optimized-enum types + diagnostics
src/LayeredCraft.OptimizedEnums.Generator/OptimizedEnumGenerator.cs Incremental generator setup + source output registration
src/LayeredCraft.OptimizedEnums.Generator/Models/LocationInfo.cs Location model + helpers for diagnostic reporting
src/LayeredCraft.OptimizedEnums.Generator/Models/EquatableArray.cs Structural-equality array wrapper for incremental caching
src/LayeredCraft.OptimizedEnums.Generator/Models/EnumInfo.cs Immutable model driving emission (members/types/diagnostics)
src/LayeredCraft.OptimizedEnums.Generator/LayeredCraft.OptimizedEnums.Generator.csproj Generator packaging + analyzer/runtime bundling
src/LayeredCraft.OptimizedEnums.Generator/Emitters/TemplateHelper.cs Embedded template loading/caching + rendering
src/LayeredCraft.OptimizedEnums.Generator/Emitters/EnumEmitter.cs Model creation + AddSource hint naming
src/LayeredCraft.OptimizedEnums.Generator/Diagnostics/DiagnosticInfo.cs Diagnostic model + reporting helpers
src/LayeredCraft.OptimizedEnums.Generator/Diagnostics/DiagnosticDescriptors.cs OE* diagnostic descriptor definitions
src/LayeredCraft.OptimizedEnums.Generator/AnalyzerReleases.Unshipped.md Roslyn analyzer release tracking (unshipped rules)
src/LayeredCraft.OptimizedEnums.Generator/AnalyzerReleases.Shipped.md Roslyn analyzer release tracking (shipped rules)
requirements.txt Python deps for MkDocs site
mkdocs.yml MkDocs Material site configuration
layeredcraft-optimized-enums-spec.md Implementation/spec document for the project
global.json SDK pinning + MTP runner config
docs/index.md Docs homepage content
docs/getting-started/installation.md Installation guide for consumers
docs/getting-started/quick-start.md Quick start guide for consumers
docs/core-concepts/how-it-works.md Explains generator approach + sample generated code
docs/core-concepts/source-generators.md Explains incremental generator trigger/pipeline
docs/core-concepts/inheritance-model.md Explains base types + inheritance triggering model
docs/usage/defining-enums.md Usage guide for defining optimized enums
docs/usage/lookups.md Usage guide for lookup/query APIs
docs/usage/string-values.md Usage guide for non-int value types (e.g., string)
docs/api-reference/base-class.md API reference for runtime base classes
docs/api-reference/generated-members.md API reference for generator-emitted members
docs/advanced/performance.md Benchmark results + perf explanation
docs/advanced/diagnostics.md Diagnostic codes and troubleshooting info
docs/advanced/aot-trimming.md AOT/trimming guidance
docs/contributing.md Contributor documentation
docs/changelog.md Changelog for the project
docs/assets/css/extra.css MkDocs site custom styling
README.md Repository/package overview and usage summary
LayeredCraft.OptimizedEnums.slnx Solution structure including docs/tests projects
Directory.Packages.props Central package version management
Directory.Build.props Shared build/package metadata configuration
.idea/.idea.LayeredCraft.OptimizedEnums/.idea/encodings.xml Rider IDE metadata (currently committed)
.idea/.idea.LayeredCraft.OptimizedEnums/.idea/.gitignore Rider IDE metadata ignore list (currently committed)
.gitignore Added ignores for IDE/config/script artifacts
.github/workflows/build.yaml Build/package workflow
.github/workflows/pr-build.yaml PR validation workflow
.github/workflows/docs.yml MkDocs build + GitHub Pages deploy workflow
.github/dependabot.yml Dependabot configuration
Files not reviewed (2)
  • .idea/.idea.LayeredCraft.OptimizedEnums/.idea/.gitignore: Language not supported
  • .idea/.idea.LayeredCraft.OptimizedEnums/.idea/encodings.xml: Language not supported
Comments suppressed due to low confidence (1)

.idea/.idea.LayeredCraft.OptimizedEnums/.idea/.gitignore:16

  • This repository is now set up to ignore .idea/ via the root .gitignore, so committing .idea metadata (like this file) will keep IDE-specific state in source control unnecessarily. Consider deleting the committed .idea directory contents and relying on the ignore rule instead.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread docs/advanced/aot-trimming.md
Comment thread src/LayeredCraft.OptimizedEnums.Generator/Providers/EnumSyntaxProvider.cs Outdated
Comment thread docs/api-reference/generated-members.md
Comment thread README.md
Comment thread docs/usage/lookups.md
Comment thread docs/usage/lookups.md
Comment thread docs/advanced/performance.md
Comment thread .idea/.idea.LayeredCraft.OptimizedEnums/.idea/encodings.xml Outdated
ncipollina and others added 2 commits March 30, 2026 15:37
…icate scan, use value equality for duplicate detection

- GetContainingTypeDeclarations now includes type parameters (MinimallyQualifiedFormat)
  and static modifier so generated partial wrappers compile for generic/static outer types
- DetectDuplicateValues now iterates all DeclaringSyntaxReferences instead of a single
  classDecl so members declared in other partial files are included in duplicate-value checks
- Switch duplicate-value dictionary key from .ToString() to raw object so value-type
  equality (e.g. decimal 1.0m == 1.00m) is used rather than string representation

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@ncipollina ncipollina merged commit ec0563f into main Mar 30, 2026
3 checks passed
@ncipollina ncipollina deleted the feat/initial-implementation branch March 30, 2026 19:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants