From 673b8cbcf4a6bd540e8773ff1993f7d56c644910 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 27 Sep 2026 09:26:36 +0000 Subject: [PATCH] fix: report an empty metadata file as unparseable, not missing [patch] GeneratorBase dropped additional files with no text before looking them up by name, so an empty things.json that was wired up correctly was reported as MetadataFileMissing ("not supplied as an AdditionalFile"), pointing the user at their .csproj instead of the file. Empty files now reach Deserialize and report MetadataParseFailed, the same as whitespace-only ones. Among duplicates of one name, a file with content is still preferred. Fixes ktsu-dev/SourceGeneratorToolkit#23 Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_014jCUYfoRMwhybsUaSa1NFm --- SourceGeneratorToolkit.Test/GeneratorBaseTests.cs | 8 +++++--- SourceGeneratorToolkit/GeneratorBase.cs | 10 +++++++--- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/SourceGeneratorToolkit.Test/GeneratorBaseTests.cs b/SourceGeneratorToolkit.Test/GeneratorBaseTests.cs index cbe8d8e..85b728b 100644 --- a/SourceGeneratorToolkit.Test/GeneratorBaseTests.cs +++ b/SourceGeneratorToolkit.Test/GeneratorBaseTests.cs @@ -150,14 +150,16 @@ public void AJsonNullDocumentIsReportedRatherThanTreatedAsEmpty() } [TestMethod] - public void AnEmptyMetadataFileCountsAsMissing() + [DataRow("")] + [DataRow(" \n\t")] + public void AnEmptyMetadataFileIsReportedAsUnparseableNotMissing(string contents) { GeneratorRunResult result = Harness.Run( new ThingsGenerator(), - new Dictionary { ["things.json"] = "" }); + new Dictionary { ["things.json"] = contents }); Assert.AreEqual(1, result.Diagnostics.Length); - Assert.AreEqual(TestDiagnostics.MetadataFileMissing.Id, result.Diagnostics[0].Id); + Assert.AreEqual(TestDiagnostics.MetadataParseFailed.Id, result.Diagnostics[0].Id, result.Diagnostics[0].GetMessage()); } [TestMethod] diff --git a/SourceGeneratorToolkit/GeneratorBase.cs b/SourceGeneratorToolkit/GeneratorBase.cs index c422c11..f69a866 100644 --- a/SourceGeneratorToolkit/GeneratorBase.cs +++ b/SourceGeneratorToolkit/GeneratorBase.cs @@ -62,15 +62,19 @@ public void Initialize(IncrementalGeneratorInitializationContext context) SourceText? sourceText = file.GetText(cancellationToken); return new MetadataFile(NameOf(file.Path), sourceText?.ToString() ?? string.Empty, sourceText, file.Path); }) - .Where(file => file.Text.Length > 0) .Collect(); context.RegisterSourceOutput(metadataFiles, (productionContext, files) => { - // A duplicate name means the same metadata reached the compilation twice; the first wins. + // A duplicate name means the same metadata reached the compilation twice; the first with + // content wins. An empty file is still present, so it is handed on and fails to parse + // rather than being reported as missing. Dictionary byName = files .GroupBy(file => file.FileName, StringComparer.Ordinal) - .ToDictionary(group => group.Key, group => group.First(), StringComparer.Ordinal); + .ToDictionary( + group => group.Key, + group => group.FirstOrDefault(file => file.Text.Length > 0) ?? group.First(), + StringComparer.Ordinal); // A missing file must say so. Producing no output and no explanation is indistinguishable // from a generator that simply had nothing to emit.