feat: add LayeredCraft.OptimizedEnums.SystemTextJson package#3
feat: add LayeredCraft.OptimizedEnums.SystemTextJson package#3ncipollina merged 14 commits intomainfrom
Conversation
Adds a new source generator package that emits zero-reflection, AOT-safe System.Text.Json converters for OptimizedEnum types. Decorate any OptimizedEnum subclass with [OptimizedEnumJsonConverter(ByName|ByValue)] and the generator stamps [JsonConverter] on a generated partial class and emits a concrete, non-generic converter calling TryFromName/TryFromValue directly. The attribute and OptimizedEnumJsonConverterType enum are injected into consuming compilations via RegisterPostInitializationOutput (no separate runtime DLL needed). Converter code is rendered via a Scriban template consistent with the main generator. Two diagnostics are emitted for invalid usage: OE2001 (must inherit OptimizedEnum) and OE2002 (must be partial). All 21 snapshot tests pass across net8.0/net9.0/net10.0. Also bumps System.Text.Json to 10.0.5 (Scriban 7.0.6 requires it) and adds SCRIBAN_NO_SYSTEM_TEXT_JSON to both generator projects so Scriban's STJ integration code is compiled out. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…he STJ package Adds a ProjectReference (ReferenceOutputAssembly=false) from the STJ generator to the main generator so that NuGet pack includes LayeredCraft.OptimizedEnums in the .nuspec dependency group. Consumers now only need to install LayeredCraft.OptimizedEnums.SystemTextJson and the core package is pulled in automatically. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…dep from STJ generator The plain ProjectReference to the main generator caused CS1703 because both projects declared Microsoft.CSharp, resulting in both lib/ and ref/ versions being added to the compile references. Since the main generator's GetDependencyTargetPaths target makes Microsoft.CSharp.dll available transitively, the STJ generator no longer needs its own direct reference, pack item, or GetDependencyTargetPaths target for it. The ProjectReference (without ReferenceOutputAssembly=false) now correctly declares LayeredCraft.OptimizedEnums as a public NuGet dependency, so consumers only need to install LayeredCraft.OptimizedEnums.SystemTextJson. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add docs/usage/json-serialization.md covering ByName/ByValue strategies, what gets generated, string-valued enums, AOT safety, and OE2xxx diagnostics - Update README with SystemTextJson NuGet badge and JSON serialization section - Update installation, quick-start, diagnostics, and changelog docs - Add json-serialization.md to mkdocs.yml nav and .slnx solution folder - Bump VersionPrefix from 1.0.0 to 1.1.0 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 79dea795ff
ℹ️ 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".
...ayeredCraft.OptimizedEnums.SystemTextJson.Generator/Providers/JsonConverterSyntaxProvider.cs
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Pull request overview
Adds a new LayeredCraft.OptimizedEnums.SystemTextJson source-generator package that emits per-type System.Text.Json converters for OptimizedEnum classes via a new [OptimizedEnumJsonConverter] attribute, plus tests and documentation.
Changes:
- Introduces
LayeredCraft.OptimizedEnums.SystemTextJson.Generatorincremental generator + Scriban template to emit[JsonConverter]-stamped partial stubs and concrete converters. - Adds snapshot-based generator tests (
Verify.SourceGenerators) forByName,ByValue, and error diagnostics (OE2001/OE2002). - Updates docs/README and bumps repo version +
System.Text.Jsonpackage version.
Reviewed changes
Copilot reviewed 51 out of 51 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/LayeredCraft.OptimizedEnums.SystemTextJson.Tests/xunit.runner.json | xUnit runner schema config for new test project |
| tests/LayeredCraft.OptimizedEnums.SystemTextJson.Tests/Snapshots/GeneratorVerifyTests.Error_NotPartial#OptimizedEnumJsonConverterAttribute.g.verified.cs | Snapshot: post-init emitted attribute source |
| tests/LayeredCraft.OptimizedEnums.SystemTextJson.Tests/Snapshots/GeneratorVerifyTests.Error_NotPartial.verified.txt | Snapshot: expected diagnostics for non-partial usage |
| tests/LayeredCraft.OptimizedEnums.SystemTextJson.Tests/Snapshots/GeneratorVerifyTests.Error_NotOptimizedEnum#OptimizedEnumJsonConverterAttribute.g.verified.cs | Snapshot: post-init emitted attribute source |
| tests/LayeredCraft.OptimizedEnums.SystemTextJson.Tests/Snapshots/GeneratorVerifyTests.Error_NotOptimizedEnum.verified.txt | Snapshot: expected diagnostics for non-OptimizedEnum usage |
| tests/LayeredCraft.OptimizedEnums.SystemTextJson.Tests/Snapshots/GeneratorVerifyTests.ByValue_WithNamespace#OptimizedEnumJsonConverterAttribute.g.verified.cs | Snapshot: post-init emitted attribute source |
| tests/LayeredCraft.OptimizedEnums.SystemTextJson.Tests/Snapshots/GeneratorVerifyTests.ByValue_WithNamespace#MyApp.Domain.OrderStatus.SystemTextJson.g.verified.cs | Snapshot: generated ByValue converter output |
| tests/LayeredCraft.OptimizedEnums.SystemTextJson.Tests/Snapshots/GeneratorVerifyTests.ByValue_WithNamespace#MyApp.Domain.OrderStatus.g.verified.cs | Snapshot: core generator output (dependency behavior) |
| tests/LayeredCraft.OptimizedEnums.SystemTextJson.Tests/Snapshots/GeneratorVerifyTests.ByValue_StringValueType#OptimizedEnumJsonConverterAttribute.g.verified.cs | Snapshot: post-init emitted attribute source |
| tests/LayeredCraft.OptimizedEnums.SystemTextJson.Tests/Snapshots/GeneratorVerifyTests.ByValue_StringValueType#MyApp.Domain.Color.SystemTextJson.g.verified.cs | Snapshot: generated ByValue converter for string TValue |
| tests/LayeredCraft.OptimizedEnums.SystemTextJson.Tests/Snapshots/GeneratorVerifyTests.ByValue_StringValueType#MyApp.Domain.Color.g.verified.cs | Snapshot: core generator output for string TValue |
| tests/LayeredCraft.OptimizedEnums.SystemTextJson.Tests/Snapshots/GeneratorVerifyTests.ByName_WithNamespace#OptimizedEnumJsonConverterAttribute.g.verified.cs | Snapshot: post-init emitted attribute source |
| tests/LayeredCraft.OptimizedEnums.SystemTextJson.Tests/Snapshots/GeneratorVerifyTests.ByName_WithNamespace#MyApp.Domain.OrderStatus.SystemTextJson.g.verified.cs | Snapshot: generated ByName converter output |
| tests/LayeredCraft.OptimizedEnums.SystemTextJson.Tests/Snapshots/GeneratorVerifyTests.ByName_WithNamespace#MyApp.Domain.OrderStatus.g.verified.cs | Snapshot: core generator output (dependency behavior) |
| tests/LayeredCraft.OptimizedEnums.SystemTextJson.Tests/Snapshots/GeneratorVerifyTests.ByName_StringValueType#OptimizedEnumJsonConverterAttribute.g.verified.cs | Snapshot: post-init emitted attribute source |
| tests/LayeredCraft.OptimizedEnums.SystemTextJson.Tests/Snapshots/GeneratorVerifyTests.ByName_StringValueType#MyApp.Domain.Color.SystemTextJson.g.verified.cs | Snapshot: generated ByName converter for string TValue |
| tests/LayeredCraft.OptimizedEnums.SystemTextJson.Tests/Snapshots/GeneratorVerifyTests.ByName_StringValueType#MyApp.Domain.Color.g.verified.cs | Snapshot: core generator output for string TValue |
| tests/LayeredCraft.OptimizedEnums.SystemTextJson.Tests/Snapshots/GeneratorVerifyTests.ByName_GlobalNamespace#Priority.SystemTextJson.g.verified.cs | Snapshot: generated ByName converter for global namespace |
| tests/LayeredCraft.OptimizedEnums.SystemTextJson.Tests/Snapshots/GeneratorVerifyTests.ByName_GlobalNamespace#Priority.g.verified.cs | Snapshot: core generator output for global namespace |
| tests/LayeredCraft.OptimizedEnums.SystemTextJson.Tests/Snapshots/GeneratorVerifyTests.ByName_GlobalNamespace#OptimizedEnumJsonConverterAttribute.g.verified.cs | Snapshot: post-init emitted attribute source |
| tests/LayeredCraft.OptimizedEnums.SystemTextJson.Tests/ModuleInitializer.cs | Initializes Verify.SourceGenerators in test module |
| tests/LayeredCraft.OptimizedEnums.SystemTextJson.Tests/LayeredCraft.OptimizedEnums.SystemTextJson.Tests.csproj | New multi-TFM test project wiring refs + packages |
| tests/LayeredCraft.OptimizedEnums.SystemTextJson.Tests/GeneratorVerifyTests.cs | Snapshot tests for new STJ generator behaviors |
| tests/LayeredCraft.OptimizedEnums.SystemTextJson.Tests/GeneratorTestHelpers.cs | Roslyn compilation + generator driver harness for snapshots |
| src/LayeredCraft.OptimizedEnums.SystemTextJson.Generator/TrackingNames.cs | Incremental generator tracking names |
| src/LayeredCraft.OptimizedEnums.SystemTextJson.Generator/Templates/JsonConverter.scriban | Scriban template for converter + partial stub emission |
| src/LayeredCraft.OptimizedEnums.SystemTextJson.Generator/Providers/JsonConverterSyntaxProvider.cs | Syntax provider extracts decorated classes + validates usage |
| src/LayeredCraft.OptimizedEnums.SystemTextJson.Generator/OptimizedEnumJsonConverterType.cs | Internal enum mirror used by generator pipeline |
| src/LayeredCraft.OptimizedEnums.SystemTextJson.Generator/OptimizedEnumJsonConverterGenerator.cs | New incremental generator entry point |
| src/LayeredCraft.OptimizedEnums.SystemTextJson.Generator/Models/LocationInfo.cs | Location model + extension helpers for diagnostics |
| src/LayeredCraft.OptimizedEnums.SystemTextJson.Generator/Models/JsonConverterInfo.cs | Immutable model driving emission |
| src/LayeredCraft.OptimizedEnums.SystemTextJson.Generator/Models/EquatableArray.cs | Equatable array utility for incremental cache friendliness |
| src/LayeredCraft.OptimizedEnums.SystemTextJson.Generator/LayeredCraft.OptimizedEnums.SystemTextJson.Generator.csproj | New packaged analyzer/generator project definition |
| src/LayeredCraft.OptimizedEnums.SystemTextJson.Generator/Emitters/TemplateHelper.cs | Loads/caches embedded Scriban templates |
| src/LayeredCraft.OptimizedEnums.SystemTextJson.Generator/Emitters/JsonConverterEmitter.cs | Builds model + emits converter source; reports internal errors |
| src/LayeredCraft.OptimizedEnums.SystemTextJson.Generator/Diagnostics/DiagnosticInfo.cs | Diagnostic wrapper + reporting helpers |
| src/LayeredCraft.OptimizedEnums.SystemTextJson.Generator/Diagnostics/DiagnosticDescriptors.cs | OE2001/OE2002 descriptors for generator validation |
| src/LayeredCraft.OptimizedEnums.SystemTextJson.Generator/AttributeSource.cs | Post-init injected attribute/enum source text |
| src/LayeredCraft.OptimizedEnums.SystemTextJson.Generator/AnalyzerReleases.Unshipped.md | Adds release-tracking entries for OE2001/OE2002 |
| src/LayeredCraft.OptimizedEnums.SystemTextJson.Generator/AnalyzerReleases.Shipped.md | Initializes shipped rules file |
| src/LayeredCraft.OptimizedEnums.Generator/LayeredCraft.OptimizedEnums.Generator.csproj | Adds SCRIBAN_NO_SYSTEM_TEXT_JSON define for Scriban build behavior |
| README.md | Documents new STJ package + usage snippet |
| mkdocs.yml | Adds JSON serialization doc page to nav |
| LayeredCraft.OptimizedEnums.slnx | Adds new generator + test project + doc file to solution |
| docs/usage/json-serialization.md | New usage guide for STJ converter generation |
| docs/getting-started/quick-start.md | Adds quick-start section demonstrating JSON serialization |
| docs/getting-started/installation.md | Adds optional STJ install instructions |
| docs/changelog.md | Notes new STJ package under Unreleased |
| docs/advanced/diagnostics.md | Documents new OE2001/OE2002 diagnostics |
| Directory.Packages.props | Pins System.Text.Json version for repo |
| Directory.Build.props | Bumps VersionPrefix to 1.1.0 |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
src/LayeredCraft.OptimizedEnums.SystemTextJson.Generator/Templates/JsonConverter.scriban
Show resolved
Hide resolved
- Switch CreateSyntaxProvider to ForAttributeWithMetadataName to prevent duplicate emissions when a partial class has the attribute on one declaration and an unrelated attribute on another - Expose AttributeMetadataName as internal const for use in generator registration - Remove manual attribute lookup in Transform; use context.Attributes[0] directly - Remove unused System.Collections.Immutable using - Fix OE2001/OE2002 diagnostic messages in docs to match exact MessageFormat strings - Clarify AOT section: converter logic is reflection-free, but STJ uses Activator.CreateInstance for converter instantiation unless JsonSerializerContext is used; add note explaining how to eliminate that in NativeAOT scenarios Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…type test - Add ValueTypeIsReferenceType to JsonConverterInfo model; populate from ITypeSymbol.IsReferenceType in provider; thread through emitter model - Conditionalize null token guard in JsonConverter.scriban on value_type_is_reference_type to fix ArgumentNullException crash when TValue is a reference type (e.g. string) and JSON token is null - Add OE9001 to AnalyzerReleases.Unshipped.md to fix pre-existing RS2000 error - Add ByName_NestedType verify test and snapshots to cover containing-type preamble/suffix code path - Update ByValue_WithNamespace and ByValue_StringValueType snapshots to reflect null-guard changes Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
@codex review |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 55 out of 55 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
src/LayeredCraft.OptimizedEnums.SystemTextJson.Generator/Emitters/JsonConverterEmitter.cs
Show resolved
Hide resolved
src/LayeredCraft.OptimizedEnums.SystemTextJson.Generator/Emitters/TemplateHelper.cs
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 76866864cb
ℹ️ 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".
src/LayeredCraft.OptimizedEnums.SystemTextJson.Generator/Templates/JsonConverter.scriban
Show resolved
Hide resolved
...ayeredCraft.OptimizedEnums.SystemTextJson.Generator/Providers/JsonConverterSyntaxProvider.cs
Show resolved
Hide resolved
- Promote OE9002 to static DiagnosticDescriptors field; remove inline descriptor from JsonConverterEmitter catch block - Add OE2003 diagnostic for unknown OptimizedEnumJsonConverterType values; validate rawValue against defined enum members in provider and return early with error diagnostic instead of silently casting - Add OE9002 and OE2003 to AnalyzerReleases.Unshipped.md - Change TemplateHelper resource name matching from InvariantCulture to Ordinal; manifest resource names are identifiers, not locale-sensitive text - Add HandleNull => true override to generated converter so STJ always invokes Read for null JSON tokens rather than silently producing null, ensuring non-null enum assumptions are enforced at deserialization - Document OE2003 in docs/advanced/diagnostics.md Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: cfa80f9608
ℹ️ 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".
src/LayeredCraft.OptimizedEnums.SystemTextJson.Generator/Templates/JsonConverter.scriban
Outdated
Show resolved
Hide resolved
Setting HandleNull to true caused Read to throw on JsonTokenType.Null and Write to dereference value without a null guard, breaking nullable scenarios like OrderStatus? properties. STJ's default HandleNull behavior (false for reference types) correctly handles null tokens/values without involving the converter. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 55 out of 55 changed files in this pull request and generated 1 comment.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
src/LayeredCraft.OptimizedEnums.SystemTextJson.Generator/Templates/JsonConverter.scriban
Show resolved
Hide resolved
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
j-d-ha
left a comment
There was a problem hiding this comment.
This is awesome!!!!
I left 2 non-blocking suggestions.
src/LayeredCraft.OptimizedEnums.SystemTextJson.Generator/Emitters/JsonConverterEmitter.cs
Show resolved
Hide resolved
mkdocs.yml
Outdated
There was a problem hiding this comment.
Given that mkdocs is more or less unmaintained, maybe look at this: https://zensical.org/
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add zensical.toml with full config converted from mkdocs.yml - Add pyproject.toml with zensical dependency for uv package management - Update docs workflow to use uv + zensical build instead of pip + mkdocs - Remove mkdocs.yml and requirements.txt - Update .slnx to reference new config files Note: run `uv lock` locally and commit uv.lock to enable --locked installs in CI Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Summary
Adds the
LayeredCraft.OptimizedEnums.SystemTextJsonpackage — a source-generated, zero-reflectionJsonConverterforOptimizedEnumtypes. Decorate a class with[OptimizedEnumJsonConverter]and the generator emits a concrete, AOT-safe converter and stamps[JsonConverter]on the partial class automatically. No manualJsonSerializerOptionsregistration is ever needed.The package declares
LayeredCraft.OptimizedEnumsas a NuGet dependency, so consumers only need a singledotnet add package.Changes
New package —
LayeredCraft.OptimizedEnums.SystemTextJsonOptimizedEnumJsonConverterGenerator— RoslynIIncrementalGeneratorwithRegisterPostInitializationOutputto inject the attribute/enum source into consuming compilations[OptimizedEnumJsonConverter(OptimizedEnumJsonConverterType.ByName | ByValue)]attributeJsonConverterEmitter— uses Scriban template (Templates/JsonConverter.scriban) to emit a concrete non-genericJsonConverter<T>per decorated classOE2001diagnostic — class does not inheritOptimizedEnum<TEnum, TValue>OE2002diagnostic — class is not declaredpartialVerify.SourceGeneratorsProjectReferenceto main generator —Microsoft.CSharp.dllflows transitively viaGetDependencyTargetPathsVersion & build
VersionPrefixbumped from1.0.0→1.1.0Directory.Packages.props:System.Text.Jsonbumped to10.0.5(required by Scriban 7.0.6 NuGet metadata);SCRIBAN_NO_SYSTEM_TEXT_JSONdefine prevents Scriban from using STJ at compile timeDocumentation
docs/usage/json-serialization.md— new page covering installation,ByName/ByValuestrategies, generated output, string-valued enums, AOT safety, diagnostics, and constraintsdocs/advanced/diagnostics.md— addedOE2001andOE2002SystemTextJson diagnostics sectiondocs/getting-started/installation.md— added optional STJ install sectiondocs/getting-started/quick-start.md— added step 6 with JSON serialization exampledocs/changelog.md— added SystemTextJson entry under UnreleasedREADME.md— updated packages table with NuGet badge; added JSON Serialization sectionmkdocs.yml— addedjson-serialization.mdto Usage navLayeredCraft.OptimizedEnums.slnx— addedjson-serialization.mdto solution folderValidation
LayeredCraft.OptimizedEnums.SystemTextJson.Testssnapshot tests pass forByName,ByValue, nested types, OE2001, and OE2002 diagnosticsLayeredCraft.OptimizedEnums.SystemTextJsonbrings in the core package automaticallyRelease Notes
New package:
LayeredCraft.OptimizedEnums.SystemTextJson(1.1.0)Add source-generated, AOT-safe
System.Text.Jsonconverters to yourOptimizedEnumtypes with a single attribute:Install with
dotnet add package LayeredCraft.OptimizedEnums.SystemTextJson— the core package is pulled in automatically.🤖 Generated with Claude Code