AGENTS.md

Build & Test Commands

# Build
dotnet build dotnet-project-file-analyzers.slnx -c Release

# Test (must filter out Generators category — CI does this too)
dotnet test dotnet-project-file-analyzers.slnx -c Release --no-build --filter TestCategory!=Generators

# Pack (version passed via -p:PackageVersion=)
dotnet pack src/DotNetProjectFile.Analyzers/DotNetProjectFile.Analyzers.csproj -c Release -p:PackageVersion=1.15.2

No separate lint/typecheck step — EnforceCodeStyleInBuild=true in props/common.props means code style rules run during dotnet build. Fix build warnings to satisfy style.

SDK & Toolchain

  • .NET SDK 10.0.300 pinned in global.json (rollForward: latestPatch).
  • Solution format: dotnet-project-file-analyzers.slnx (new XML-based SLNX, not legacy .sln).
  • C# 14.0, nullable enabled, netstandard2.0 for the analyzer itself, net10.0 for tests.

Architecture

This is a Roslyn analyzer package (160+ diagnostics) for .NET project files (.csproj, .vbproj, .resx, NuGet.config, .editorconfig, .slnx, INI).

Path Purpose  
.net.csproj SDK Allows DotNetProjectFile.Analyzers to run Roslyn Analyzers on MSBuild files. Ignore it.
src/DotNetProjectFile.Analyzers/ Main analyzer library (netstandard2.0)  
src/DotNetProjectFile.RuleCatalog/ Rule metadata collection & NuGet package introspection (net10.0)  
src/.../Analyzers/ Analyzer implementations (MsBuild, Resx, Ini, NuGetConfig, Slnx, Generic)  
src/.../Rule.cs (+ partials) All DiagnosticDescriptor definitions  
src/.../build/ MSBuild .props/.targets shipped in the NuGet package  
specs/Specs/ Unit tests (NUnit)  
specs/TestData/ Shared test data (embedded files)  
specs/Bench/ Benchmarks (BenchmarkDotNet)  
projects/ 120+ fixture projects used as test input data  
props/common.props Shared MSBuild properties for all projects  

Rule numbering: Proj00xx general, Proj02xx packaging, Proj03xx NuGet config, Proj05xx licensing, Proj08xx CPM, Proj17xx formatting, Proj2xxx RESX, Proj3xxx generic, Proj4xxx INI/EditorConfig, Proj5xxx SLNX.

Testing Quirks

  • Tests use NUnit 4 + Verify (snapshot testing) + CodeAnalysis.TestTools.
  • Verify snapshots: .verified.txt is the baseline; .received.txt is generated on failure. Accept by replacing verified with received.
  • specs/TestData/ is a separate project embedding files from specs/TestData/Files/.
  • Fixture projects in projects/ are linked into the Specs project as <None> items.
  • Windows-specific tests use DefineConstants: Is_Windows conditional compilation.
  • CI always runs with --filter TestCategory!=Generators.

Code Style

  • .editorconfig: 4-space indent for .cs; 2-space indent for .csproj/.props/.targets/.slnx.
  • Expression-bodied members preferred for methods, properties, constructors, accessors, indexers, operators.
  • Multiple Roslyn analyzer packages enforce style: StyleCop, SonarAnalyzer, Qowaiv, AsyncFixer.
  • RestoreLockedMode enforced in CI — after changing dependencies, run dotnet restore --force-evaluate to update packages.lock.json.

CI

  • Build workflow (build-publish.yml): build → test (with TestCategory!=Generators filter) → pack on tag → publish to NuGet.org.
  • Dependabot: weekly NuGet + GitHub Actions updates.
  • Spell/grammar checks on docs/** via LanguageTool and Misspell reviewdog workflows.

Adding a New Diagnostic

  1. Add a DiagnosticDescriptor property in Rule.cs (or the relevant partial: Rule.Ini.cs, Rule.NuGet.cs, Rule.RESX.cs, Rule.SLNX.cs).
  2. Implement the analyzer in the appropriate Analyzers/ subdirectory.
  3. Add test fixture projects under projects/ if needed.
  4. Add tests under specs/Specs/ matching the source structure.
  5. Update docs/ with the new rule documentation:
    • Identify the category of the rule (e.g., SLNX, MSBuild, Packaging, Publishing, Test projects, Licensing, Central Package Management, Resource file rules, Generic, NuGet configuration, INI, .globalconfig, .editorconfig, JSON, Analyzers, Other, Design, Formatting).
    • Create docs/rules/ProjXXXX.md where ProjXXXX is the rule ID:
      • Use the exact Jekyll front matter template:
        ---
        parent: <CategoryName>
        ancestor: Rules
        permalink: /rules/ProjXXXX
        ---
        
      • Use a title of the format # ProjXXXX: Rule Name.
      • Provide a clear explanation of why the rule exists and how to address it.
      • Include ## Non-compliant and ## Compliant code blocks showing examples of the bad practice and its fix.
    • Update docs/README.md:
      • Locate the correct category header in the document.
      • Add the new rule link in sequential/numerical order: * [**ProjXXXX** Rule Name](rules/ProjXXXX.md)
    • Update src/DotNetProjectFile.Analyzers/README.md:
      • Locate the correct category header in the document.
      • Add the new rule link in sequential/numerical order: * [**ProjXXXX** Rule Name](https://dotnet-project-file-analyzers.github.io/rules/ProjXXXX.html)

Gotchas

  • Do not modify .net.csproj: This file is exclusively for running Roslyn Analyzers. Agents must completely ignore and skip this file during development.
  • Do not modify or read src/DotNetProjectFile.RuleCatalog/Data/DiagnosticCollection.json: This file is huge, and is data about analyzers.
  • Do not commit, any change, or check the GIT history of this repo unless explictly asked.
  • Only run related tests, and never if you only changed documentation.