Skip to content

Commit 7e70556

Browse files
committed
Add AGENTS.md
1 parent 7a42405 commit 7e70556

File tree

3 files changed

+114
-1
lines changed

3 files changed

+114
-1
lines changed

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -251,4 +251,7 @@ tools/*
251251
BenchmarkDotNet.Artifacts
252252

253253
# Nuke.build files
254-
.nuke/build.schema.json
254+
.nuke/build.schema.json
255+
256+
# AI agents
257+
.claude/

AGENTS.md

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
# AGENTS.md
2+
3+
This file provides guidance to AI coding agents when working with code in this repository.
4+
5+
## Project Overview
6+
7+
NetEscapades.EnumGenerators is a C# source generator that creates high-performance extension methods for enums, replacing slow reflection-based `Enum.ToString()`, `Enum.IsDefined()`, `Enum.Parse()`, etc. with compile-time generated switch-based alternatives. It also includes Roslyn analyzers (with code fixes) that suggest using the generated methods, and an interceptor generator that automatically replaces standard enum method calls.
8+
9+
## Build Commands
10+
11+
This project uses [Nuke](https://nuke.build/) for builds. The solution file is `NetEscapades.EnumGenerators.sln`.
12+
13+
```bash
14+
# Build
15+
./build.cmd Compile # Windows
16+
./build.sh Compile # Unix
17+
18+
# Run all tests (unit + integration)
19+
./build.cmd Test
20+
./build.sh Test
21+
22+
# Run a single test project directly
23+
dotnet test tests/NetEscapades.EnumGenerators.Tests
24+
25+
# Run a single test by name
26+
dotnet test tests/NetEscapades.EnumGenerators.Tests --filter "FullyQualifiedName~CanGenerateEnumExtensionsInGlobalNamespace"
27+
28+
# Pack NuGet packages
29+
./build.cmd Pack
30+
31+
# Full CI pipeline (clean + test + package tests)
32+
./build.cmd Clean Test TestPackage
33+
```
34+
35+
## Architecture
36+
37+
### NuGet Package Structure (6 packages)
38+
39+
The project ships as multiple packages to avoid forcing runtime dependencies:
40+
41+
- **NetEscapades.EnumGenerators** — meta-package referencing Generators + RuntimeDependencies
42+
- **NetEscapades.EnumGenerators.Generators** — the source generator + analyzers (netstandard2.0)
43+
- **NetEscapades.EnumGenerators.Attributes**`[EnumExtensions]` attribute (netstandard2.0, net451)
44+
- **NetEscapades.EnumGenerators.RuntimeDependencies**`EnumParseOptions`, `SerializationOptions`, `SerializationTransform` types (netstandard2.0, net451)
45+
- **NetEscapades.EnumGenerators.Interceptors** — C# 12+ interceptor generator (netstandard2.0)
46+
- **NetEscapades.EnumGenerators.Interceptors.Attributes**`[Interceptable<T>]` attribute
47+
48+
### Source Generator Pipeline (`src/NetEscapades.EnumGenerators.Generators/`)
49+
50+
- **EnumGenerator.cs**`IIncrementalGenerator` entry point. Uses `ForAttributeWithMetadataName` to find enums decorated with `[EnumExtensions]` or `[EnumExtensions<T>]`. Extracts `EnumToGenerate` model from syntax/semantic analysis.
51+
- **SourceGenerationHelper.cs** (~2300 lines) — Generates the extension class source code via `StringBuilder`. Produces `ToStringFast()`, `IsDefined()`, `TryParse()`, `Parse()`, `GetValues()`, `GetNames()`, `HasFlagFast()`, etc. Handles multiple code paths: with/without System.Memory, with/without runtime dependencies, C# 14 field keyword support, collection expressions.
52+
- **EnumToGenerate.cs** — Immutable model capturing everything needed to generate code for one enum (name, namespace, underlying type, members, flags, metadata source). Must implement `IEquatable<T>` correctly for incremental caching.
53+
- **TrackingNames.cs** — String constants for incremental generator step tracking, used in tests to verify caching behavior.
54+
55+
### Analyzers (`src/NetEscapades.EnumGenerators.Generators/Diagnostics/`)
56+
57+
Two categories:
58+
59+
**Definition Analyzers** (always on) — validate `[EnumExtensions]` usage:
60+
- `DuplicateEnumValueAnalyzer` — warns about duplicate enum values
61+
- `DuplicateExtensionClassAnalyzer` — warns about conflicting extension class names
62+
- `EnumInGenericTypeAnalyzer` — warns about enums nested in generic types
63+
64+
**Usage Analyzers** (NEEG004–NEEG012, opt-in via `EnumGenerator_EnableUsageAnalyzers`) — suggest using generated methods instead of framework methods:
65+
- Each has a paired `CodeFixProvider` for automatic fixes
66+
- Controlled by `build_property.EnumGenerator_EnableUsageAnalyzers` in `.editorconfig`
67+
- Pattern: analyzer detects `Enum.Method()` call on a decorated enum, code fix replaces with `EnumExtensions.MethodFast()`
68+
69+
### Interceptors (`src/NetEscapades.EnumGenerators.Interceptors/`)
70+
71+
- **InterceptorGenerator.cs** — C# 12+ feature. Intercepts `ToString()` and `HasFlag()` calls at compile time and replaces them with generated fast versions.
72+
- Requires .NET 8.0.400+ SDK, controlled by `EnumGenerator_EnableInterception` MSBuild property.
73+
74+
### Key Design Constraints
75+
76+
- **Generators target netstandard2.0** — must run inside any version of the Roslyn compiler. Cannot use modern .NET APIs directly; uses `Polyfill` package for compatibility.
77+
- **Incremental generator caching**`EnumToGenerate` and all pipeline outputs must correctly implement equality. Tests verify this by running the generator twice and asserting all outputs are `Cached` or `Unchanged` on the second run.
78+
- **No Roslyn symbols in outputs** — the generator must not store `ISymbol`, `Compilation`, or `SyntaxNode` objects in pipeline outputs (would break caching). `TestHelpers.AssertObjectGraph` validates this.
79+
80+
## Testing
81+
82+
### Test Projects
83+
84+
- **NetEscapades.EnumGenerators.Tests** — main test project with:
85+
- **Snapshot tests** (Verify.Xunit) for generated source output, stored in `tests/.../Snapshots/`. Use `dotnet tool run dotnet-verify accept` or manually update `.verified.` files when output intentionally changes.
86+
- **Generator tests** (`EnumGeneratorTests.cs`) — feed source code strings through `TestHelpers.GetGeneratedOutput()`, assert no diagnostics, verify output with Verify snapshots.
87+
- **Analyzer tests** — use `Microsoft.CodeAnalysis.Testing` framework. Each inherits `AnalyzerTestsBase<TAnalyzer, TCodeFixer>` providing `VerifyAnalyzerAsync`/`VerifyCodeFixAsync` helpers.
88+
- **Incremental caching tests** — every generator test automatically runs twice to verify caching correctness.
89+
- **Integration test projects** — test the actual NuGet packages work correctly in various configurations (NetStandard, System.Memory, Interceptors, PrivateAssets).
90+
- **Benchmarks** — BenchmarkDotNet project comparing generated methods vs. framework methods.
91+
92+
### Test Patterns
93+
94+
- Generator tests use `TestHelpers.Options` record to configure source input, language version, analyzer options, and features.
95+
- Snapshot files use parameter-based naming: `TestName_param1_param2.verified.txt`.
96+
- Version strings in generated code are scrubbed via `ScrubExpectedChanges()` to avoid snapshot churn on version bumps.
97+
98+
## Version Management
99+
100+
- Version is defined in `version.props` (`VersionPrefix` + `VersionSuffix`).
101+
- `Constants.cs` in the generators project also contains the version string used in `[GeneratedCode]` attributes.
102+
- Both must be updated together when changing versions.
103+
104+
## MSBuild Properties (user-facing configuration)
105+
106+
- `EnumGenerator_EnumMetadataSource` — default metadata source attribute (EnumMemberAttribute, DisplayAttribute, DescriptionAttribute, None)
107+
- `EnumGenerator_ForceInternal` — force all generated extension classes to be internal
108+
- `EnumGenerator_EnableUsageAnalyzers` — enable usage analyzers (default: false)
109+
- `EnableEnumGeneratorInterceptor` — enable interceptor generator

CLAUDE.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
@AGENTS.md

0 commit comments

Comments
 (0)