diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json new file mode 100644 index 00000000..e463006f --- /dev/null +++ b/.config/dotnet-tools.json @@ -0,0 +1,13 @@ +{ + "version": 1, + "isRoot": true, + "tools": { + "dotnet-t4": { + "version": "3.0.0", + "commands": [ + "t4" + ], + "rollForward": false + } + } +} \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 59a22f74..e524f79f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -28,6 +28,9 @@ jobs: cache: true cache-dependency-path: '**/packages.lock.json' + - name: Restore tools + run: dotnet tool restore + - name: Restore run: dotnet restore Linq2GraphQL.CI.slnf --locked-mode diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index a2169e36..7c27d797 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -25,6 +25,9 @@ jobs: cache: true cache-dependency-path: '**/packages.lock.json' + - name: Restore tools + run: dotnet tool restore + - name: Publish working-directory: docs/Linq2GraphQL.Docs run: dotnet publish -c:Release -o:publish diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6bc60275..f2bc6d80 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -31,6 +31,9 @@ jobs: id: nbgv - run: echo 'SemVer2=${{ steps.nbgv.outputs.SemVer2 }}' + - name: Restore tools + run: dotnet tool restore + - name: Restore run: dotnet restore Linq2GraphQL.Release.slnf --locked-mode diff --git a/.gitignore b/.gitignore index d6151772..9e118511 100644 --- a/.gitignore +++ b/.gitignore @@ -369,3 +369,6 @@ FodyWeavers.xsd .build-timestamp config.json local-nuget/ + +# Preprocessed T4 templates (generated at build time by dotnet-t4) +src/Linq2GraphQL.Generator/Templates/**/*.g.cs diff --git a/CLAUDE.md b/CLAUDE.md index 5aa7f1b4..9eb69778 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -55,7 +55,7 @@ Key details that bite: `ClientGenerator.GenerateAsync` posts an introspection query (`General.IntrospectionQuery`, or the `IncludeDeprecated` variant), deserializes into `GraphQLSchema/RootSchema`, and drives one T4 template per output kind (`Templates/{Client,Class,Interface,Methods,Enum,Scalars}`). Templates return `FileEntry` objects; `Program.cs` writes them with `ReplaceLineEndings("\n")` — generated files are always LF, keep it that way. -**T4 workflow (from DEVELOPER.md — read it before touching templates):** each template is three files — `X.tt` (source, edit this), `X.tt.cs` (hand-written partial with constructor params and helpers), and `X.cs` (preprocessed output, **checked in**). Editing a `.tt` does nothing until the `.cs` is regenerated via Visual Studio's *Run Custom Tool* on the `.tt` file. There is no CLI equivalent wired up, so a template change made outside Visual Studio will silently build and run the old logic. +**T4 workflow (from DEVELOPER.md — read it before touching templates):** each template is three files — `X.tt` (source, edit this), `X.tt.cs` (hand-written partial with constructor params and helpers), and `X.g.cs` (preprocessed output, **generated at build time, gitignored**). The generator's csproj runs the pinned `dotnet-t4` local tool (`.config/dotnet-tools.json`) over every `Templates\**\*.tt` before compiling, so editing a `.tt` and building is the whole loop and stale template logic cannot be built. Compile errors inside template code are reported against the `.tt` file and line. A template in a new folder needs a `T4Template` item with a `TemplateNamespace` in the csproj. `GeneratorSettings.Current.Nullable` is ambient static state read from inside templates; the nullable and non-nullable clients differ mainly in nullable annotations and `#pragma warning disable CS8618`. diff --git a/DEVELOPER.md b/DEVELOPER.md index 80df6442..9aca6f75 100644 --- a/DEVELOPER.md +++ b/DEVELOPER.md @@ -13,9 +13,11 @@ This document provides comprehensive guidance for developers working on the Linq ## Prerequisites -- **Visual Studio 2022** (recommended) or Visual Studio 2019/2022 -- **.NET 8.0 SDK** or later -- **T4 Template Support** - Ensure the "Text Template Transformation" workload is installed in Visual Studio +- **.NET 10.0 SDK** or later +- **Any editor** - Visual Studio, Rider, VS Code or plain `dotnet build` all work; + T4 preprocessing runs as part of the build, so no IDE-specific tooling is required +- **`dotnet tool restore`** once per clone, to fetch the pinned `dotnet-t4` CLI tool + (the build does this for you) ## Project Structure @@ -27,7 +29,8 @@ src/ │ │ ├── Class/ # Class generation templates │ │ ├── Interface/ # Interface generation templates │ │ ├── Methods/ # Method generation templates -│ │ └── Enum/ # Enum generation templates +│ │ ├── Enum/ # Enum generation templates +│ │ └── Scalars/ # Custom scalar templates │ ├── GraphQLSchema/ # Schema parsing and processing │ └── ClientGenerator.cs # Main generation orchestration └── Linq2GraphQL.Client/ # Core client library @@ -43,7 +46,8 @@ This project uses **T4 (Text Template Transformation Toolkit)** for code generat - **`.tt`** - Source T4 template files (human-editable) - **`.tt.cs`** - Partial class definitions for template variables and helper methods -- **`.cs`** - Preprocessed T4 templates (auto-generated, contains the actual `TransformText()` method) +- **`.g.cs`** - Preprocessed T4 templates (contains the actual `TransformText()` method). + **Generated at build time, gitignored, never checked in.** ### Template Development Workflow @@ -52,27 +56,44 @@ This project uses **T4 (Text Template Transformation Toolkit)** for code generat When modifying `.tt` files: 1. **Edit the `.tt` file** with your changes -2. **Manually regenerate the `.cs` file** using Visual Studio's custom tool -3. **Build the project** to ensure compilation -4. **Test the generation** by running the client generator +2. **Build the project** - the `.g.cs` file is regenerated automatically +3. **Test the generation** by running the client generator -#### 2. Manual Template Regeneration +That is the whole loop. There is no manual regeneration step, and no way to build +stale template logic: compile errors in a template point straight back at the +`.tt` file and line number. -**⚠️ IMPORTANT: After modifying any `.tt` file, you MUST manually regenerate the corresponding `.cs` file.** +#### 2. How Build-Time Preprocessing Works -**In Visual Studio 2022:** +`Linq2GraphQL.Generator.csproj` preprocesses every `Templates\**\*.tt` into a +sibling `