From d38cc15a3649240b3133f0650f91855bb4518a57 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 21 Aug 2026 19:51:30 +0000 Subject: [PATCH 01/14] test: preserve standalone date member names Co-authored-by: jorgerangel-msft <102122018+jorgerangel-msft@users.noreply.github.com> --- .../test/Providers/ParameterProviderTests.cs | 4 ++-- .../test/Providers/PropertyProviderTests.cs | 4 ++-- .../test/Utilities/CSharpNameExtensionsTests.cs | 6 ++++-- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ParameterProviderTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ParameterProviderTests.cs index 0646f57b13b..8741a2e8fbc 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ParameterProviderTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ParameterProviderTests.cs @@ -117,8 +117,8 @@ private static IEnumerable DateTimeParameterNameTestCases() { ("startTime", dateTime, "startOn"), ("createdAt", dateTime, "createdOn"), - ("timestamp", dateTime, "on"), - ("date", InputPrimitiveType.PlainDate, "on"), + ("timestamp", dateTime, "timestamp"), + ("date", InputPrimitiveType.PlainDate, "date"), ("modifiedAt", dateTime.WithNullable(true), "modifiedOn"), ("expirationDate", dateTime, "expireOn"), ("creationDate", dateTime, "createdOn"), diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/PropertyProviderTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/PropertyProviderTests.cs index 379b15849bf..5bd9adb5941 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/PropertyProviderTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/PropertyProviderTests.cs @@ -284,7 +284,7 @@ private static IEnumerable DateTimePropertyNameTestCases() yield return new TestCaseData("CreatedAt", dateTime, false, "CreatedOn"); yield return new TestCaseData("DeletionTimestamp", dateTime, false, "DeletedOn"); yield return new TestCaseData("ModificationTimeStamp", dateTime, false, "ModifiedOn"); - yield return new TestCaseData("Timestamp", dateTime, false, "On"); + yield return new TestCaseData("Timestamp", dateTime, false, "Timestamp"); yield return new TestCaseData("ExpirationDate", dateTime, false, "ExpireOn"); yield return new TestCaseData("CreationDate", dateTime, false, "CreatedOn"); yield return new TestCaseData("CreationTime", dateTime, false, "CreatedOn"); @@ -292,7 +292,7 @@ private static IEnumerable DateTimePropertyNameTestCases() yield return new TestCaseData("DeletionDateTime", dateTime, false, "DeletedOn"); yield return new TestCaseData("AccountExpirationDate", dateTime, false, "AccountExpirationOn"); yield return new TestCaseData("RecordedAt", InputPrimitiveType.String, false, "RecordedAt"); - yield return new TestCaseData("Date", InputPrimitiveType.PlainDate, false, "On"); + yield return new TestCaseData("Date", InputPrimitiveType.PlainDate, false, "Date"); yield return new TestCaseData("SnapshotTimestamp", dateTime.WithNullable(true), false, "SnapshotOn"); yield return new TestCaseData("StatusTimestamp", dateTime.WithNullable(true), false, "StatusTimestamp"); yield return new TestCaseData("LastSyncTimestamp", dateTime, false, "LastSyncOn"); diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Utilities/CSharpNameExtensionsTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Utilities/CSharpNameExtensionsTests.cs index d184095d067..cb8842d2f29 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Utilities/CSharpNameExtensionsTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Utilities/CSharpNameExtensionsTests.cs @@ -43,8 +43,10 @@ private static IEnumerable DateTimeNameTestCases() InputPrimitiveType.String); yield return new TestCaseData("startTime", dateTime, "startOn"); - yield return new TestCaseData("Date", InputPrimitiveType.PlainDate, "On"); - yield return new TestCaseData("date", InputPrimitiveType.PlainDate, "on"); + yield return new TestCaseData("Date", InputPrimitiveType.PlainDate, "Date"); + yield return new TestCaseData("date", InputPrimitiveType.PlainDate, "date"); + yield return new TestCaseData("Timestamp", dateTime, "Timestamp"); + yield return new TestCaseData("timestamp", dateTime, "timestamp"); yield return new TestCaseData("fromTime", dateTime, "fromTime"); yield return new TestCaseData("toDate", dateTime, "toDate"); yield return new TestCaseData("pointInTime", dateTime, "pointInTime"); From 6ebd670efb88d58cb480f1139d54a877875a833d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 21 Aug 2026 19:52:32 +0000 Subject: [PATCH 02/14] fix: preserve standalone date member names Co-authored-by: jorgerangel-msft <102122018+jorgerangel-msft@users.noreply.github.com> --- .../src/Shared/CSharpNameExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Shared/CSharpNameExtensions.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Shared/CSharpNameExtensions.cs index 8d56efd8a5e..bc76638a9e9 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Shared/CSharpNameExtensions.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Shared/CSharpNameExtensions.cs @@ -68,7 +68,7 @@ public static string NormalizeDateTimeSuffix(this string name) } var suffixLength = DateTimeNameRules.GetSuffixLength(name); - if (suffixLength == 0) + if (suffixLength == 0 || suffixLength == name.Length) { return name; } From c5ff33cca7dc381811bb5ce2725770f235e5e7ad Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 21 Aug 2026 20:03:44 +0000 Subject: [PATCH 03/14] test: update standalone timestamp expectations Co-authored-by: jorgerangel-msft <102122018+jorgerangel-msft@users.noreply.github.com> --- .../XmlSerializationHandlesNullableDateTimeOffsetProperty.cs | 4 ++-- .../XmlDeserializationTests.cs | 2 +- .../MrwSerializationTypeDefinitions/XmlSerializationTests.cs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/TestData/XmlSerializationTests/XmlSerializationHandlesNullableDateTimeOffsetProperty.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/TestData/XmlSerializationTests/XmlSerializationHandlesNullableDateTimeOffsetProperty.cs index a2e945aa23e..a64a6102cfb 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/TestData/XmlSerializationTests/XmlSerializationHandlesNullableDateTimeOffsetProperty.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/TestData/XmlSerializationTests/XmlSerializationHandlesNullableDateTimeOffsetProperty.cs @@ -63,10 +63,10 @@ internal virtual void XmlModelWriteCore(global::System.Xml.XmlWriter writer, glo throw new global::System.FormatException($"The model {nameof(global::Sample.Models.TestXmlModel)} does not support writing '{format}' format."); } - if (global::Sample.Optional.IsDefined(On)) + if (global::Sample.Optional.IsDefined(Timestamp)) { writer.WriteStartElement("timestamp"); - writer.WriteStringValue(On.Value, "O"); + writer.WriteStringValue(Timestamp.Value, "O"); writer.WriteEndElement(); } } diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/XmlDeserializationTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/XmlDeserializationTests.cs index 52666216903..c34ae949f14 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/XmlDeserializationTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/XmlDeserializationTests.cs @@ -261,7 +261,7 @@ public void XmlDeserializationHandlesDateTimeOffsetProperty() Assert.IsNotNull(xmlDeserializationMethod); var methodBody = xmlDeserializationMethod!.BodyStatements!.ToDisplayString(); - Assert.IsTrue(methodBody.Contains("@on = child.GetDateTimeOffset(\"O\")"), + Assert.IsTrue(methodBody.Contains("timestamp = child.GetDateTimeOffset(\"O\")"), $"DateTimeOffset property should use child.GetDateTimeOffset(\"O\") with RFC3339 format. Actual:\n{methodBody}"); } diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/XmlSerializationTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/XmlSerializationTests.cs index 563329b08be..b1ed7dcb2b7 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/XmlSerializationTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/XmlSerializationTests.cs @@ -335,7 +335,7 @@ public void XmlSerializationHandlesDateTimeOffsetProperty() Assert.IsNotNull(xmlSerializationMethod); var methodBody = xmlSerializationMethod!.BodyStatements!.ToDisplayString(); - Assert.IsTrue(methodBody.Contains("writer.WriteStringValue(On.Value, \"O\")"), + Assert.IsTrue(methodBody.Contains("writer.WriteStringValue(Timestamp.Value, \"O\")"), $"DateTimeOffset property should be serialized with WriteStringValue. Actual:\n{methodBody}"); } From 5f376081212a88370b50f565e625654de2fd0f89 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 21 Aug 2026 20:25:52 +0000 Subject: [PATCH 04/14] fix: honor normalized CodeGenMember property names Co-authored-by: jorgerangel-msft <102122018+jorgerangel-msft@users.noreply.github.com> --- .../src/Providers/TypeProvider.cs | 2 ++ .../ModelProviders/ModelCustomizationTests.cs | 25 +++++++++++++++++++ .../MockInputModel.cs | 14 +++++++++++ 3 files changed, 41 insertions(+) create mode 100644 packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CustomCodeReplacesDateNormalizedProperty/MockInputModel.cs diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/TypeProvider.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/TypeProvider.cs index 4687727365e..b0396dd786b 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/TypeProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/TypeProvider.cs @@ -444,6 +444,7 @@ internal PropertyProvider[] FilterCustomizedProperties(IEnumerable await Helpers.GetCompilationFromDirectoryAsync()); + + var modelTypeProvider = mockGenerator.Object.OutputLibrary.TypeProviders.Single(t => t.Name == "MockInputModel"); + + Assert.AreEqual(1, modelTypeProvider.CustomCodeView!.Properties.Count); + Assert.AreEqual("Created", modelTypeProvider.CustomCodeView.Properties[0].Name); + Assert.AreEqual(0, modelTypeProvider.Properties.Count); + Assert.AreEqual(1, modelTypeProvider.CanonicalView!.Properties.Count); + Assert.AreEqual("Created", modelTypeProvider.CanonicalView.Properties[0].Name); + } + [Test] public async Task CustomCodeWinsOverIsExactNameOnModel() { diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CustomCodeReplacesDateNormalizedProperty/MockInputModel.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CustomCodeReplacesDateNormalizedProperty/MockInputModel.cs new file mode 100644 index 00000000000..85f56e669c6 --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CustomCodeReplacesDateNormalizedProperty/MockInputModel.cs @@ -0,0 +1,14 @@ +#nullable disable + +using Sample; +using SampleTypeSpec; +using Microsoft.TypeSpec.Generator.Customizations; + +namespace Sample.Models +{ + public partial class MockInputModel + { + [CodeGenMember("CreatedAt")] + public System.DateTimeOffset Created { get; set; } + } +} From 3bd56ec54ae56c265bf9ff0bfe3e770d471641c0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 21 Aug 2026 20:44:07 +0000 Subject: [PATCH 05/14] fix(csharp-generator): scope normalized CodeGenMember property matching Co-authored-by: jorgerangel-msft <102122018+jorgerangel-msft@users.noreply.github.com> --- .../src/Providers/TypeProvider.cs | 59 +++++++++++++++---- .../ModelProviders/ModelCustomizationTests.cs | 26 +++++++- .../MockInputModel.cs | 2 +- .../MockInputModel.cs | 14 +++++ 4 files changed, 87 insertions(+), 14 deletions(-) create mode 100644 packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/DateNormalizedCodeGenMemberDoesNotSuppressExactNameProperty/MockInputModel.cs diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/TypeProvider.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/TypeProvider.cs index b0396dd786b..366cffab1ee 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/TypeProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/TypeProvider.cs @@ -435,27 +435,18 @@ protected static bool IsResolvableBuildableType(CSharpType type) => internal PropertyProvider[] FilterCustomizedProperties(IEnumerable specProperties) { + var dateNormalizedSpecPropertyNames = BuildDateNormalizedSpecPropertyNames(specProperties); var properties = new List(); var customProperties = new HashSet(); foreach (var customProperty in BuildAllCustomProperties()) { - customProperties.Add(customProperty.Name); - if (customProperty.OriginalName != null) - { - customProperties.Add(customProperty.OriginalName); - customProperties.Add(customProperty.OriginalName.NormalizeCSharpAcronyms(normalizeDateTimeSuffix: true)); - } + AddCustomName(customProperties, customProperty.Name, customProperty.OriginalName, dateNormalizedSpecPropertyNames); } foreach (var customField in BuildAllCustomFields()) { - customProperties.Add(customField.Name); - if (customField.OriginalName != null) - { - customProperties.Add(customField.OriginalName); - customProperties.Add(customField.OriginalName.NormalizeCSharpAcronyms(normalizeDateTimeSuffix: true)); - } + AddCustomName(customProperties, customField.Name, customField.OriginalName, dateNormalizedSpecPropertyNames); } foreach (var property in specProperties) @@ -469,6 +460,50 @@ internal PropertyProvider[] FilterCustomizedProperties(IEnumerable customNames, + string name, + string? originalName, + IReadOnlyDictionary dateNormalizedSpecPropertyNames) + { + customNames.Add(name); + if (originalName is null) + { + return; + } + + customNames.Add(originalName); + if (dateNormalizedSpecPropertyNames.TryGetValue(originalName, out var normalizedName)) + { + customNames.Add(normalizedName); + } + } + + private static IReadOnlyDictionary BuildDateNormalizedSpecPropertyNames(IEnumerable specProperties) + { + var normalizedSpecPropertyNames = new Dictionary(StringComparer.Ordinal); + + foreach (var specProperty in specProperties) + { + var inputProperty = specProperty.InputProperty; + if (inputProperty is null || inputProperty.IsExactName || !inputProperty.Type.IsDateTimeInputType()) + { + continue; + } + + var identifierName = inputProperty.Name.ToIdentifierName(); + if (specProperty.Name == identifierName) + { + continue; + } + + normalizedSpecPropertyNames.TryAdd(inputProperty.Name, specProperty.Name); + normalizedSpecPropertyNames.TryAdd(identifierName, specProperty.Name); + } + + return normalizedSpecPropertyNames; + } + internal FieldProvider[] FilterCustomizedFields(IEnumerable specFields) { var fields = new List(); diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/ModelCustomizationTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/ModelCustomizationTests.cs index 880be1ae1f2..d95baf5537e 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/ModelCustomizationTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/ModelCustomizationTests.cs @@ -163,7 +163,7 @@ public async Task CustomCodeReplacesDateNormalizedProperty() InputPrimitiveType.String); var inputModel = InputFactory.Model( "mockInputModel", - properties: [InputFactory.Property("createdAt", dateTime, isRequired: true)]); + properties: [InputFactory.Property("creationDate", dateTime, isRequired: true)]); var mockGenerator = await MockHelpers.LoadMockGeneratorAsync( inputModelTypes: [inputModel], @@ -178,6 +178,30 @@ public async Task CustomCodeReplacesDateNormalizedProperty() Assert.AreEqual("Created", modelTypeProvider.CanonicalView.Properties[0].Name); } + [Test] + public async Task DateNormalizedCodeGenMemberDoesNotSuppressExactNameProperty() + { + var dateTime = new InputDateTimeType( + DateTimeKnownEncoding.Rfc3339, + "utcDateTime", + "TypeSpec.utcDateTime", + InputPrimitiveType.String); + var inputModel = InputFactory.Model( + "mockInputModel", + properties: [InputFactory.Property("CreatedOn", dateTime, isRequired: true, isExactName: true)]); + + var mockGenerator = await MockHelpers.LoadMockGeneratorAsync( + inputModelTypes: [inputModel], + compilation: async () => await Helpers.GetCompilationFromDirectoryAsync()); + + var modelTypeProvider = mockGenerator.Object.OutputLibrary.TypeProviders.Single(t => t.Name == "MockInputModel"); + + Assert.AreEqual(1, modelTypeProvider.CustomCodeView!.Properties.Count); + Assert.AreEqual("Created", modelTypeProvider.CustomCodeView.Properties[0].Name); + Assert.AreEqual(1, modelTypeProvider.Properties.Count); + Assert.AreEqual("CreatedOn", modelTypeProvider.Properties[0].Name); + } + [Test] public async Task CustomCodeWinsOverIsExactNameOnModel() { diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CustomCodeReplacesDateNormalizedProperty/MockInputModel.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CustomCodeReplacesDateNormalizedProperty/MockInputModel.cs index 85f56e669c6..a4772bc7a87 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CustomCodeReplacesDateNormalizedProperty/MockInputModel.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CustomCodeReplacesDateNormalizedProperty/MockInputModel.cs @@ -8,7 +8,7 @@ namespace Sample.Models { public partial class MockInputModel { - [CodeGenMember("CreatedAt")] + [CodeGenMember("CreationDate")] public System.DateTimeOffset Created { get; set; } } } diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/DateNormalizedCodeGenMemberDoesNotSuppressExactNameProperty/MockInputModel.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/DateNormalizedCodeGenMemberDoesNotSuppressExactNameProperty/MockInputModel.cs new file mode 100644 index 00000000000..85f56e669c6 --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/DateNormalizedCodeGenMemberDoesNotSuppressExactNameProperty/MockInputModel.cs @@ -0,0 +1,14 @@ +#nullable disable + +using Sample; +using SampleTypeSpec; +using Microsoft.TypeSpec.Generator.Customizations; + +namespace Sample.Models +{ + public partial class MockInputModel + { + [CodeGenMember("CreatedAt")] + public System.DateTimeOffset Created { get; set; } + } +} From 3a07cbd2ab8923ba66916610ecd6304c8a4ec813 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 21 Aug 2026 20:54:37 +0000 Subject: [PATCH 06/14] fix(csharp-generator): normalize CodeGenMember mappings Co-authored-by: jorgerangel-msft <102122018+jorgerangel-msft@users.noreply.github.com> --- .../src/Providers/TypeProvider.cs | 29 ++++++++----------- .../ModelProviders/ModelCustomizationTests.cs | 20 +++++++++++++ .../MockInputModel.cs | 14 +++++++++ 3 files changed, 46 insertions(+), 17 deletions(-) create mode 100644 packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CustomCodeReplacesAcronymNormalizedProperty/MockInputModel.cs diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/TypeProvider.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/TypeProvider.cs index 366cffab1ee..96a3206af84 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/TypeProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/TypeProvider.cs @@ -435,18 +435,18 @@ protected static bool IsResolvableBuildableType(CSharpType type) => internal PropertyProvider[] FilterCustomizedProperties(IEnumerable specProperties) { - var dateNormalizedSpecPropertyNames = BuildDateNormalizedSpecPropertyNames(specProperties); + var specPropertiesByName = BuildSpecPropertiesByName(specProperties); var properties = new List(); var customProperties = new HashSet(); foreach (var customProperty in BuildAllCustomProperties()) { - AddCustomName(customProperties, customProperty.Name, customProperty.OriginalName, dateNormalizedSpecPropertyNames); + AddCustomName(customProperties, customProperty.Name, customProperty.OriginalName, specPropertiesByName); } foreach (var customField in BuildAllCustomFields()) { - AddCustomName(customProperties, customField.Name, customField.OriginalName, dateNormalizedSpecPropertyNames); + AddCustomName(customProperties, customField.Name, customField.OriginalName, specPropertiesByName); } foreach (var property in specProperties) @@ -464,7 +464,7 @@ private static void AddCustomName( HashSet customNames, string name, string? originalName, - IReadOnlyDictionary dateNormalizedSpecPropertyNames) + IReadOnlyDictionary specPropertiesByName) { customNames.Add(name); if (originalName is null) @@ -473,35 +473,30 @@ private static void AddCustomName( } customNames.Add(originalName); - if (dateNormalizedSpecPropertyNames.TryGetValue(originalName, out var normalizedName)) + if (specPropertiesByName.TryGetValue(originalName, out var inputProperty) && !inputProperty.IsExactName) { - customNames.Add(normalizedName); + customNames.Add(originalName.NormalizeCSharpAcronyms(inputProperty.Type.IsDateTimeInputType())); } } - private static IReadOnlyDictionary BuildDateNormalizedSpecPropertyNames(IEnumerable specProperties) + private static IReadOnlyDictionary BuildSpecPropertiesByName(IEnumerable specProperties) { - var normalizedSpecPropertyNames = new Dictionary(StringComparer.Ordinal); + var specPropertiesByName = new Dictionary(StringComparer.Ordinal); foreach (var specProperty in specProperties) { var inputProperty = specProperty.InputProperty; - if (inputProperty is null || inputProperty.IsExactName || !inputProperty.Type.IsDateTimeInputType()) + if (inputProperty is null) { continue; } var identifierName = inputProperty.Name.ToIdentifierName(); - if (specProperty.Name == identifierName) - { - continue; - } - - normalizedSpecPropertyNames.TryAdd(inputProperty.Name, specProperty.Name); - normalizedSpecPropertyNames.TryAdd(identifierName, specProperty.Name); + specPropertiesByName.TryAdd(inputProperty.Name, inputProperty); + specPropertiesByName.TryAdd(identifierName, inputProperty); } - return normalizedSpecPropertyNames; + return specPropertiesByName; } internal FieldProvider[] FilterCustomizedFields(IEnumerable specFields) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/ModelCustomizationTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/ModelCustomizationTests.cs index d95baf5537e..e5abb7dcf36 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/ModelCustomizationTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/ModelCustomizationTests.cs @@ -178,6 +178,26 @@ public async Task CustomCodeReplacesDateNormalizedProperty() Assert.AreEqual("Created", modelTypeProvider.CanonicalView.Properties[0].Name); } + [Test] + public async Task CustomCodeReplacesAcronymNormalizedProperty() + { + var inputModel = InputFactory.Model( + "mockInputModel", + properties: [InputFactory.Property("ipAddress", InputPrimitiveType.String, isRequired: true)]); + + var mockGenerator = await MockHelpers.LoadMockGeneratorAsync( + inputModelTypes: [inputModel], + compilation: async () => await Helpers.GetCompilationFromDirectoryAsync()); + + var modelTypeProvider = mockGenerator.Object.OutputLibrary.TypeProviders.Single(t => t.Name == "MockInputModel"); + + Assert.AreEqual(1, modelTypeProvider.CustomCodeView!.Properties.Count); + Assert.AreEqual("Address", modelTypeProvider.CustomCodeView.Properties[0].Name); + Assert.AreEqual(0, modelTypeProvider.Properties.Count); + Assert.AreEqual(1, modelTypeProvider.CanonicalView!.Properties.Count); + Assert.AreEqual("Address", modelTypeProvider.CanonicalView.Properties[0].Name); + } + [Test] public async Task DateNormalizedCodeGenMemberDoesNotSuppressExactNameProperty() { diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CustomCodeReplacesAcronymNormalizedProperty/MockInputModel.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CustomCodeReplacesAcronymNormalizedProperty/MockInputModel.cs new file mode 100644 index 00000000000..cc63077eb51 --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CustomCodeReplacesAcronymNormalizedProperty/MockInputModel.cs @@ -0,0 +1,14 @@ +#nullable disable + +using Sample; +using SampleTypeSpec; +using Microsoft.TypeSpec.Generator.Customizations; + +namespace Sample.Models +{ + public partial class MockInputModel + { + [CodeGenMember("IpAddress")] + public string Address { get; set; } + } +} From 8936e7b9c59da4b54de0b5f62076012d161de430 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 21 Aug 2026 21:12:26 +0000 Subject: [PATCH 07/14] test(csharp-generator): map emitted date property name Co-authored-by: jorgerangel-msft <102122018+jorgerangel-msft@users.noreply.github.com> --- .../CustomCodeReplacesDateNormalizedProperty/MockInputModel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CustomCodeReplacesDateNormalizedProperty/MockInputModel.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CustomCodeReplacesDateNormalizedProperty/MockInputModel.cs index a4772bc7a87..c109728521b 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CustomCodeReplacesDateNormalizedProperty/MockInputModel.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CustomCodeReplacesDateNormalizedProperty/MockInputModel.cs @@ -8,7 +8,7 @@ namespace Sample.Models { public partial class MockInputModel { - [CodeGenMember("CreationDate")] + [CodeGenMember("CreatedOn")] public System.DateTimeOffset Created { get; set; } } } From 2e8a8334a3f6171feb513e3354ccbdb4e732a8d6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 21 Aug 2026 22:03:17 +0000 Subject: [PATCH 08/14] test(csharp-generator): refine normalized member mappings Co-authored-by: jorgerangel-msft <102122018+jorgerangel-msft@users.noreply.github.com> --- .../ModelProviders/ModelCustomizationTests.cs | 15 ++++++++------- .../MockInputModel.cs | 4 ++-- .../MockInputModel.cs | 2 +- 3 files changed, 11 insertions(+), 10 deletions(-) rename packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/{DateNormalizedCodeGenMemberDoesNotSuppressExactNameProperty => ExactNameCodeGenMemberReplacesProperty}/MockInputModel.cs (86%) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/ModelCustomizationTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/ModelCustomizationTests.cs index e5abb7dcf36..7645832efab 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/ModelCustomizationTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/ModelCustomizationTests.cs @@ -183,7 +183,7 @@ public async Task CustomCodeReplacesAcronymNormalizedProperty() { var inputModel = InputFactory.Model( "mockInputModel", - properties: [InputFactory.Property("ipAddress", InputPrimitiveType.String, isRequired: true)]); + properties: [InputFactory.Property("ipFoo", InputPrimitiveType.String, isRequired: true)]); var mockGenerator = await MockHelpers.LoadMockGeneratorAsync( inputModelTypes: [inputModel], @@ -192,14 +192,14 @@ public async Task CustomCodeReplacesAcronymNormalizedProperty() var modelTypeProvider = mockGenerator.Object.OutputLibrary.TypeProviders.Single(t => t.Name == "MockInputModel"); Assert.AreEqual(1, modelTypeProvider.CustomCodeView!.Properties.Count); - Assert.AreEqual("Address", modelTypeProvider.CustomCodeView.Properties[0].Name); + Assert.AreEqual("Foo", modelTypeProvider.CustomCodeView.Properties[0].Name); Assert.AreEqual(0, modelTypeProvider.Properties.Count); Assert.AreEqual(1, modelTypeProvider.CanonicalView!.Properties.Count); - Assert.AreEqual("Address", modelTypeProvider.CanonicalView.Properties[0].Name); + Assert.AreEqual("Foo", modelTypeProvider.CanonicalView.Properties[0].Name); } [Test] - public async Task DateNormalizedCodeGenMemberDoesNotSuppressExactNameProperty() + public async Task ExactNameCodeGenMemberReplacesProperty() { var dateTime = new InputDateTimeType( DateTimeKnownEncoding.Rfc3339, @@ -208,7 +208,7 @@ public async Task DateNormalizedCodeGenMemberDoesNotSuppressExactNameProperty() InputPrimitiveType.String); var inputModel = InputFactory.Model( "mockInputModel", - properties: [InputFactory.Property("CreatedOn", dateTime, isRequired: true, isExactName: true)]); + properties: [InputFactory.Property("CreatedFoo", dateTime, isRequired: true, isExactName: true)]); var mockGenerator = await MockHelpers.LoadMockGeneratorAsync( inputModelTypes: [inputModel], @@ -218,8 +218,9 @@ public async Task DateNormalizedCodeGenMemberDoesNotSuppressExactNameProperty() Assert.AreEqual(1, modelTypeProvider.CustomCodeView!.Properties.Count); Assert.AreEqual("Created", modelTypeProvider.CustomCodeView.Properties[0].Name); - Assert.AreEqual(1, modelTypeProvider.Properties.Count); - Assert.AreEqual("CreatedOn", modelTypeProvider.Properties[0].Name); + Assert.AreEqual(0, modelTypeProvider.Properties.Count); + Assert.AreEqual(1, modelTypeProvider.CanonicalView!.Properties.Count); + Assert.AreEqual("Created", modelTypeProvider.CanonicalView.Properties[0].Name); } [Test] diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CustomCodeReplacesAcronymNormalizedProperty/MockInputModel.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CustomCodeReplacesAcronymNormalizedProperty/MockInputModel.cs index cc63077eb51..fa6c79f4128 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CustomCodeReplacesAcronymNormalizedProperty/MockInputModel.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CustomCodeReplacesAcronymNormalizedProperty/MockInputModel.cs @@ -8,7 +8,7 @@ namespace Sample.Models { public partial class MockInputModel { - [CodeGenMember("IpAddress")] - public string Address { get; set; } + [CodeGenMember("IPFoo")] + public string Foo { get; set; } } } diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/DateNormalizedCodeGenMemberDoesNotSuppressExactNameProperty/MockInputModel.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/ExactNameCodeGenMemberReplacesProperty/MockInputModel.cs similarity index 86% rename from packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/DateNormalizedCodeGenMemberDoesNotSuppressExactNameProperty/MockInputModel.cs rename to packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/ExactNameCodeGenMemberReplacesProperty/MockInputModel.cs index 85f56e669c6..4425a8ca8d0 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/DateNormalizedCodeGenMemberDoesNotSuppressExactNameProperty/MockInputModel.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/ExactNameCodeGenMemberReplacesProperty/MockInputModel.cs @@ -8,7 +8,7 @@ namespace Sample.Models { public partial class MockInputModel { - [CodeGenMember("CreatedAt")] + [CodeGenMember("CreatedFoo")] public System.DateTimeOffset Created { get; set; } } } From 6d45b4f2901f5749286e7b81aa8f7998b2bf1882 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 21 Aug 2026 22:11:16 +0000 Subject: [PATCH 09/14] fix(csharp-generator): normalize expiration names to expires Co-authored-by: jorgerangel-msft <102122018+jorgerangel-msft@users.noreply.github.com> --- .../src/Shared/CSharpNameExtensions.cs | 20 +++++++++++++------ .../test/Providers/ParameterProviderTests.cs | 7 ++++--- .../test/Providers/PropertyProviderTests.cs | 7 ++++--- .../Utilities/CSharpNameExtensionsTests.cs | 11 ++++++---- 4 files changed, 29 insertions(+), 16 deletions(-) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Shared/CSharpNameExtensions.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Shared/CSharpNameExtensions.cs index bc76638a9e9..1e342ddb4e8 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Shared/CSharpNameExtensions.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Shared/CSharpNameExtensions.cs @@ -101,20 +101,28 @@ private static class DateTimeNameRules { ["Creation"] = "Created", ["Deletion"] = "Deleted", - ["Expiration"] = "Expire", + ["Expiration"] = "Expires", ["Modification"] = "Modified" }; internal static string ToVerbForm(string prefix) { - if (!_nounToVerbMap.TryGetValue(prefix, out var verb)) + if (_nounToVerbMap.TryGetValue(prefix, out var verb)) { - return prefix; + return char.IsLower(prefix[0]) + ? char.ToLowerInvariant(verb[0]) + verb[1..] + : verb; } - return char.IsLower(prefix[0]) - ? char.ToLowerInvariant(verb[0]) + verb[1..] - : verb; + const string expiration = "Expiration"; + if (prefix.Length > expiration.Length && + prefix.EndsWith(expiration, StringComparison.OrdinalIgnoreCase) && + char.IsUpper(prefix[^expiration.Length])) + { + return prefix[..^expiration.Length] + "Expires"; + } + + return prefix; } internal static bool HasExcludedComponent(string name) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ParameterProviderTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ParameterProviderTests.cs index 8741a2e8fbc..b968873693a 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ParameterProviderTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ParameterProviderTests.cs @@ -120,13 +120,14 @@ private static IEnumerable DateTimeParameterNameTestCases() ("timestamp", dateTime, "timestamp"), ("date", InputPrimitiveType.PlainDate, "date"), ("modifiedAt", dateTime.WithNullable(true), "modifiedOn"), - ("expirationDate", dateTime, "expireOn"), + ("expirationDate", dateTime, "expiresOn"), ("creationDate", dateTime, "createdOn"), ("creationTime", dateTime, "createdOn"), - ("expirationDateTime", dateTime.WithNullable(true), "expireOn"), + ("expirationDateTime", dateTime.WithNullable(true), "expiresOn"), ("deletionDateTime", dateTime, "deletedOn"), ("modificationTime", dateTime, "modifiedOn"), - ("accountExpirationDate", dateTime, "accountExpirationOn"), + ("modelExpirationDate", dateTime, "modelExpiresOn"), + ("accountExpirationDate", dateTime, "accountExpiresOn"), ("statusTimestamp", dateTime.WithNullable(true), "statusTimestamp"), ("lastSyncTimestamp", dateTime, "lastSyncOn"), ("totalTime", dateTime, "totalTime"), diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/PropertyProviderTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/PropertyProviderTests.cs index 5bd9adb5941..7301cb4c525 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/PropertyProviderTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/PropertyProviderTests.cs @@ -285,12 +285,13 @@ private static IEnumerable DateTimePropertyNameTestCases() yield return new TestCaseData("DeletionTimestamp", dateTime, false, "DeletedOn"); yield return new TestCaseData("ModificationTimeStamp", dateTime, false, "ModifiedOn"); yield return new TestCaseData("Timestamp", dateTime, false, "Timestamp"); - yield return new TestCaseData("ExpirationDate", dateTime, false, "ExpireOn"); + yield return new TestCaseData("ExpirationDate", dateTime, false, "ExpiresOn"); yield return new TestCaseData("CreationDate", dateTime, false, "CreatedOn"); yield return new TestCaseData("CreationTime", dateTime, false, "CreatedOn"); - yield return new TestCaseData("ExpirationDateTime", dateTime.WithNullable(true), false, "ExpireOn"); + yield return new TestCaseData("ExpirationDateTime", dateTime.WithNullable(true), false, "ExpiresOn"); yield return new TestCaseData("DeletionDateTime", dateTime, false, "DeletedOn"); - yield return new TestCaseData("AccountExpirationDate", dateTime, false, "AccountExpirationOn"); + yield return new TestCaseData("modelExpirationDate", dateTime, false, "ModelExpiresOn"); + yield return new TestCaseData("AccountExpirationDate", dateTime, false, "AccountExpiresOn"); yield return new TestCaseData("RecordedAt", InputPrimitiveType.String, false, "RecordedAt"); yield return new TestCaseData("Date", InputPrimitiveType.PlainDate, false, "Date"); yield return new TestCaseData("SnapshotTimestamp", dateTime.WithNullable(true), false, "SnapshotOn"); diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Utilities/CSharpNameExtensionsTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Utilities/CSharpNameExtensionsTests.cs index cb8842d2f29..6042ac3afdb 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Utilities/CSharpNameExtensionsTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Utilities/CSharpNameExtensionsTests.cs @@ -58,10 +58,13 @@ private static IEnumerable DateTimeNameTestCases() yield return new TestCaseData("finishedTime", dateTime, "finishedOn"); yield return new TestCaseData("CreationTime", dateTime, "CreatedOn"); yield return new TestCaseData("creationTime", dateTime, "createdOn"); - yield return new TestCaseData("ExpirationDateTime", dateTime, "ExpireOn"); - yield return new TestCaseData("expirationDateTime", dateTime, "expireOn"); - yield return new TestCaseData("AccountExpirationDate", dateTime, "AccountExpirationOn"); - yield return new TestCaseData("accountExpirationDate", dateTime, "accountExpirationOn"); + yield return new TestCaseData("ExpirationDate", dateTime, "ExpiresOn"); + yield return new TestCaseData("expirationDate", dateTime, "expiresOn"); + yield return new TestCaseData("ExpirationDateTime", dateTime, "ExpiresOn"); + yield return new TestCaseData("expirationDateTime", dateTime, "expiresOn"); + yield return new TestCaseData("modelExpirationDate", dateTime, "modelExpiresOn"); + yield return new TestCaseData("AccountExpirationDate", dateTime, "AccountExpiresOn"); + yield return new TestCaseData("accountExpirationDate", dateTime, "accountExpiresOn"); yield return new TestCaseData("RecreationTime", dateTime, "RecreationOn"); yield return new TestCaseData("recreationTime", dateTime, "recreationOn"); yield return new TestCaseData("TotalTime", dateTime, "TotalTime"); From af853be2692fecb6ebfe04a0ead15cb40488e1e7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 21 Aug 2026 22:18:40 +0000 Subject: [PATCH 10/14] test(csharp-generator): snapshot customized normalized members Co-authored-by: jorgerangel-msft <102122018+jorgerangel-msft@users.noreply.github.com> --- .../ModelProviders/ModelCustomizationTests.cs | 3 +++ ...acesAcronymNormalizedProperty(Expected).cs | 23 +++++++++++++++++ ...eplacesDateNormalizedProperty(Expected).cs | 23 +++++++++++++++++ ...CodeGenMemberReplacesProperty(Expected).cs | 25 +++++++++++++++++++ 4 files changed, 74 insertions(+) create mode 100644 packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CustomCodeReplacesAcronymNormalizedProperty(Expected).cs create mode 100644 packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CustomCodeReplacesDateNormalizedProperty(Expected).cs create mode 100644 packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/ExactNameCodeGenMemberReplacesProperty(Expected).cs diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/ModelCustomizationTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/ModelCustomizationTests.cs index 7645832efab..478aee169d5 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/ModelCustomizationTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/ModelCustomizationTests.cs @@ -176,6 +176,7 @@ public async Task CustomCodeReplacesDateNormalizedProperty() Assert.AreEqual(0, modelTypeProvider.Properties.Count); Assert.AreEqual(1, modelTypeProvider.CanonicalView!.Properties.Count); Assert.AreEqual("Created", modelTypeProvider.CanonicalView.Properties[0].Name); + Assert.AreEqual($"{Helpers.GetExpectedFromFile("Expected")}\n", new TypeProviderWriter(modelTypeProvider).Write().Content); } [Test] @@ -196,6 +197,7 @@ public async Task CustomCodeReplacesAcronymNormalizedProperty() Assert.AreEqual(0, modelTypeProvider.Properties.Count); Assert.AreEqual(1, modelTypeProvider.CanonicalView!.Properties.Count); Assert.AreEqual("Foo", modelTypeProvider.CanonicalView.Properties[0].Name); + Assert.AreEqual($"{Helpers.GetExpectedFromFile("Expected")}\n", new TypeProviderWriter(modelTypeProvider).Write().Content); } [Test] @@ -221,6 +223,7 @@ public async Task ExactNameCodeGenMemberReplacesProperty() Assert.AreEqual(0, modelTypeProvider.Properties.Count); Assert.AreEqual(1, modelTypeProvider.CanonicalView!.Properties.Count); Assert.AreEqual("Created", modelTypeProvider.CanonicalView.Properties[0].Name); + Assert.AreEqual($"{Helpers.GetExpectedFromFile("Expected")}\n", new TypeProviderWriter(modelTypeProvider).Write().Content); } [Test] diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CustomCodeReplacesAcronymNormalizedProperty(Expected).cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CustomCodeReplacesAcronymNormalizedProperty(Expected).cs new file mode 100644 index 00000000000..6859a87975f --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CustomCodeReplacesAcronymNormalizedProperty(Expected).cs @@ -0,0 +1,23 @@ +// + +#nullable disable + +using System; +using System.Collections.Generic; + +namespace Sample.Models +{ + public partial class MockInputModel + { + private protected readonly global::System.Collections.Generic.IDictionary _additionalBinaryDataProperties; + + public MockInputModel() + { + } + + internal MockInputModel(global::System.Collections.Generic.IDictionary additionalBinaryDataProperties) + { + _additionalBinaryDataProperties = additionalBinaryDataProperties; + } + } +} \ No newline at end of file diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CustomCodeReplacesDateNormalizedProperty(Expected).cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CustomCodeReplacesDateNormalizedProperty(Expected).cs new file mode 100644 index 00000000000..6859a87975f --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CustomCodeReplacesDateNormalizedProperty(Expected).cs @@ -0,0 +1,23 @@ +// + +#nullable disable + +using System; +using System.Collections.Generic; + +namespace Sample.Models +{ + public partial class MockInputModel + { + private protected readonly global::System.Collections.Generic.IDictionary _additionalBinaryDataProperties; + + public MockInputModel() + { + } + + internal MockInputModel(global::System.Collections.Generic.IDictionary additionalBinaryDataProperties) + { + _additionalBinaryDataProperties = additionalBinaryDataProperties; + } + } +} \ No newline at end of file diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/ExactNameCodeGenMemberReplacesProperty(Expected).cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/ExactNameCodeGenMemberReplacesProperty(Expected).cs new file mode 100644 index 00000000000..6e182036f55 --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/ExactNameCodeGenMemberReplacesProperty(Expected).cs @@ -0,0 +1,25 @@ +// + +#nullable disable + +using System; +using System.Collections.Generic; + +namespace Sample.Models +{ + public partial class MockInputModel + { + private protected readonly global::System.Collections.Generic.IDictionary _additionalBinaryDataProperties; + + public MockInputModel(global::System.DateTimeOffset created) + { + Created = created; + } + + internal MockInputModel(global::System.DateTimeOffset created, global::System.Collections.Generic.IDictionary additionalBinaryDataProperties) + { + Created = created; + _additionalBinaryDataProperties = additionalBinaryDataProperties; + } + } +} \ No newline at end of file From 84a5848902ace94a09145b01fba6b6ef45fa0a34 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 21 Aug 2026 22:31:14 +0000 Subject: [PATCH 11/14] fix(csharp-generator): reuse noun mappings for date names Co-authored-by: jorgerangel-msft <102122018+jorgerangel-msft@users.noreply.github.com> --- .../src/Shared/CSharpNameExtensions.cs | 12 +++++++----- .../test/Utilities/CSharpNameExtensionsTests.cs | 1 + 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Shared/CSharpNameExtensions.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Shared/CSharpNameExtensions.cs index 1e342ddb4e8..db42276027c 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Shared/CSharpNameExtensions.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Shared/CSharpNameExtensions.cs @@ -114,12 +114,14 @@ internal static string ToVerbForm(string prefix) : verb; } - const string expiration = "Expiration"; - if (prefix.Length > expiration.Length && - prefix.EndsWith(expiration, StringComparison.OrdinalIgnoreCase) && - char.IsUpper(prefix[^expiration.Length])) + foreach (var (noun, compoundVerb) in _nounToVerbMap) { - return prefix[..^expiration.Length] + "Expires"; + if (prefix.Length > noun.Length && + prefix.EndsWith(noun, StringComparison.OrdinalIgnoreCase) && + char.IsUpper(prefix[^noun.Length])) + { + return prefix[..^noun.Length] + compoundVerb; + } } return prefix; diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Utilities/CSharpNameExtensionsTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Utilities/CSharpNameExtensionsTests.cs index 6042ac3afdb..39b8765f984 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Utilities/CSharpNameExtensionsTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Utilities/CSharpNameExtensionsTests.cs @@ -65,6 +65,7 @@ private static IEnumerable DateTimeNameTestCases() yield return new TestCaseData("modelExpirationDate", dateTime, "modelExpiresOn"); yield return new TestCaseData("AccountExpirationDate", dateTime, "AccountExpiresOn"); yield return new TestCaseData("accountExpirationDate", dateTime, "accountExpiresOn"); + yield return new TestCaseData("AccountCreationDate", dateTime, "AccountCreatedOn"); yield return new TestCaseData("RecreationTime", dateTime, "RecreationOn"); yield return new TestCaseData("recreationTime", dateTime, "recreationOn"); yield return new TestCaseData("TotalTime", dateTime, "TotalTime"); From a731b056770b0d0f8b214f45c7c1d6b79e2391e9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 21 Aug 2026 22:44:13 +0000 Subject: [PATCH 12/14] fix(csharp-generator): preserve custom required property metadata Co-authored-by: jorgerangel-msft <102122018+jorgerangel-msft@users.noreply.github.com> --- .../src/Providers/CanonicalTypeProvider.cs | 11 ++++++++++- .../ModelProviders/ModelCustomizationTests.cs | 6 ++++++ ...CodeReplacesAcronymNormalizedProperty(Expected).cs | 9 +++++++-- ...tomCodeReplacesDateNormalizedProperty(Expected).cs | 6 ++++-- 4 files changed, 27 insertions(+), 5 deletions(-) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/CanonicalTypeProvider.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/CanonicalTypeProvider.cs index 90e71ace797..131d0cd3508 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/CanonicalTypeProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/CanonicalTypeProvider.cs @@ -29,7 +29,16 @@ public CanonicalTypeProvider(TypeProvider generatedTypeProvider, InputType? inpu _generatedTypeProvider = generatedTypeProvider; var inputModel = inputType as InputModelType; _specProperties = inputModel?.Properties ?? []; - _specPropertiesMap = _specProperties.ToDictionary(p => p.IsExactName ? p.Name : p.Name.ToIdentifierName(), p => p); + _specPropertiesMap = []; + foreach (var property in _specProperties) + { + var name = property.IsExactName ? property.Name : property.Name.ToIdentifierName(); + _specPropertiesMap.TryAdd(name, property); + if (!property.IsExactName) + { + _specPropertiesMap.TryAdd(name.NormalizeCSharpAcronyms(property.Type.IsDateTimeInputType()), property); + } + } _serializedNameMap = BuildSerializationNameMap(); _renamedProperties = (_generatedTypeProvider.CustomCodeView?.Properties ?? []) .Where(p => p.OriginalName != null).Select(p => p.OriginalName!).ToHashSet(); diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/ModelCustomizationTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/ModelCustomizationTests.cs index 478aee169d5..0347b721f21 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/ModelCustomizationTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/ModelCustomizationTests.cs @@ -197,6 +197,12 @@ public async Task CustomCodeReplacesAcronymNormalizedProperty() Assert.AreEqual(0, modelTypeProvider.Properties.Count); Assert.AreEqual(1, modelTypeProvider.CanonicalView!.Properties.Count); Assert.AreEqual("Foo", modelTypeProvider.CanonicalView.Properties[0].Name); + Assert.IsTrue(modelTypeProvider.CanonicalView.Properties[0].WireInfo!.IsRequired); + Assert.IsFalse(modelTypeProvider.CanonicalView.Properties[0].WireInfo!.IsReadOnly); + Assert.IsTrue(modelTypeProvider.CanonicalView.Properties[0].Body.HasSetter); + CollectionAssert.AreEqual( + new[] { "foo" }, + modelTypeProvider.Constructors.Single(c => c.Signature.Modifiers == MethodSignatureModifiers.Public).Signature.Parameters.Select(p => p.Name)); Assert.AreEqual($"{Helpers.GetExpectedFromFile("Expected")}\n", new TypeProviderWriter(modelTypeProvider).Write().Content); } diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CustomCodeReplacesAcronymNormalizedProperty(Expected).cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CustomCodeReplacesAcronymNormalizedProperty(Expected).cs index 6859a87975f..ba7b54eca61 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CustomCodeReplacesAcronymNormalizedProperty(Expected).cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CustomCodeReplacesAcronymNormalizedProperty(Expected).cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; +using Sample; namespace Sample.Models { @@ -11,12 +12,16 @@ public partial class MockInputModel { private protected readonly global::System.Collections.Generic.IDictionary _additionalBinaryDataProperties; - public MockInputModel() + public MockInputModel(string foo) { + global::Sample.Argument.AssertNotNull(foo, nameof(foo)); + + Foo = foo; } - internal MockInputModel(global::System.Collections.Generic.IDictionary additionalBinaryDataProperties) + internal MockInputModel(string foo, global::System.Collections.Generic.IDictionary additionalBinaryDataProperties) { + Foo = foo; _additionalBinaryDataProperties = additionalBinaryDataProperties; } } diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CustomCodeReplacesDateNormalizedProperty(Expected).cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CustomCodeReplacesDateNormalizedProperty(Expected).cs index 6859a87975f..6e182036f55 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CustomCodeReplacesDateNormalizedProperty(Expected).cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CustomCodeReplacesDateNormalizedProperty(Expected).cs @@ -11,12 +11,14 @@ public partial class MockInputModel { private protected readonly global::System.Collections.Generic.IDictionary _additionalBinaryDataProperties; - public MockInputModel() + public MockInputModel(global::System.DateTimeOffset created) { + Created = created; } - internal MockInputModel(global::System.Collections.Generic.IDictionary additionalBinaryDataProperties) + internal MockInputModel(global::System.DateTimeOffset created, global::System.Collections.Generic.IDictionary additionalBinaryDataProperties) { + Created = created; _additionalBinaryDataProperties = additionalBinaryDataProperties; } } From 190437ba1a3319e1722e735dcf409850a45ea9d0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 21 Aug 2026 23:38:40 +0000 Subject: [PATCH 13/14] fix(csharp-generator): map raw CodeGenMember names through identifier normalization Co-authored-by: jorgerangel-msft <102122018+jorgerangel-msft@users.noreply.github.com> --- .../src/Providers/CanonicalTypeProvider.cs | 1 + .../src/Providers/TypeProvider.cs | 5 +++- .../ModelProviders/ModelCustomizationTests.cs | 26 +++++++++++++++++++ ...lizedPropertyUsingRawSpecName(Expected).cs | 25 ++++++++++++++++++ .../MockInputModel.cs | 14 ++++++++++ 5 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CustomCodeReplacesDateNormalizedPropertyUsingRawSpecName(Expected).cs create mode 100644 packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CustomCodeReplacesDateNormalizedPropertyUsingRawSpecName/MockInputModel.cs diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/CanonicalTypeProvider.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/CanonicalTypeProvider.cs index 131d0cd3508..85724f998e0 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/CanonicalTypeProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/CanonicalTypeProvider.cs @@ -33,6 +33,7 @@ public CanonicalTypeProvider(TypeProvider generatedTypeProvider, InputType? inpu foreach (var property in _specProperties) { var name = property.IsExactName ? property.Name : property.Name.ToIdentifierName(); + _specPropertiesMap.TryAdd(property.Name, property); _specPropertiesMap.TryAdd(name, property); if (!property.IsExactName) { diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/TypeProvider.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/TypeProvider.cs index 96a3206af84..a37fc49b7c6 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/TypeProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/TypeProvider.cs @@ -475,7 +475,10 @@ private static void AddCustomName( customNames.Add(originalName); if (specPropertiesByName.TryGetValue(originalName, out var inputProperty) && !inputProperty.IsExactName) { - customNames.Add(originalName.NormalizeCSharpAcronyms(inputProperty.Type.IsDateTimeInputType())); + customNames.Add( + originalName + .ToIdentifierName() + .NormalizeCSharpAcronyms(inputProperty.Type.IsDateTimeInputType())); } } diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/ModelCustomizationTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/ModelCustomizationTests.cs index 0347b721f21..5dfa310e73a 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/ModelCustomizationTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/ModelCustomizationTests.cs @@ -179,6 +179,32 @@ public async Task CustomCodeReplacesDateNormalizedProperty() Assert.AreEqual($"{Helpers.GetExpectedFromFile("Expected")}\n", new TypeProviderWriter(modelTypeProvider).Write().Content); } + [Test] + public async Task CustomCodeReplacesDateNormalizedPropertyUsingRawSpecName() + { + var dateTime = new InputDateTimeType( + DateTimeKnownEncoding.Rfc3339, + "utcDateTime", + "TypeSpec.utcDateTime", + InputPrimitiveType.String); + var inputModel = InputFactory.Model( + "mockInputModel", + properties: [InputFactory.Property("creationDate", dateTime, isRequired: true)]); + + var mockGenerator = await MockHelpers.LoadMockGeneratorAsync( + inputModelTypes: [inputModel], + compilation: async () => await Helpers.GetCompilationFromDirectoryAsync()); + + var modelTypeProvider = mockGenerator.Object.OutputLibrary.TypeProviders.Single(t => t.Name == "MockInputModel"); + + Assert.AreEqual(1, modelTypeProvider.CustomCodeView!.Properties.Count); + Assert.AreEqual("Created", modelTypeProvider.CustomCodeView.Properties[0].Name); + Assert.AreEqual(0, modelTypeProvider.Properties.Count); + Assert.AreEqual(1, modelTypeProvider.CanonicalView!.Properties.Count); + Assert.AreEqual("Created", modelTypeProvider.CanonicalView.Properties[0].Name); + Assert.AreEqual($"{Helpers.GetExpectedFromFile("Expected")}\n", new TypeProviderWriter(modelTypeProvider).Write().Content); + } + [Test] public async Task CustomCodeReplacesAcronymNormalizedProperty() { diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CustomCodeReplacesDateNormalizedPropertyUsingRawSpecName(Expected).cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CustomCodeReplacesDateNormalizedPropertyUsingRawSpecName(Expected).cs new file mode 100644 index 00000000000..6e182036f55 --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CustomCodeReplacesDateNormalizedPropertyUsingRawSpecName(Expected).cs @@ -0,0 +1,25 @@ +// + +#nullable disable + +using System; +using System.Collections.Generic; + +namespace Sample.Models +{ + public partial class MockInputModel + { + private protected readonly global::System.Collections.Generic.IDictionary _additionalBinaryDataProperties; + + public MockInputModel(global::System.DateTimeOffset created) + { + Created = created; + } + + internal MockInputModel(global::System.DateTimeOffset created, global::System.Collections.Generic.IDictionary additionalBinaryDataProperties) + { + Created = created; + _additionalBinaryDataProperties = additionalBinaryDataProperties; + } + } +} \ No newline at end of file diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CustomCodeReplacesDateNormalizedPropertyUsingRawSpecName/MockInputModel.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CustomCodeReplacesDateNormalizedPropertyUsingRawSpecName/MockInputModel.cs new file mode 100644 index 00000000000..b0e47831b0a --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ModelProviders/TestData/ModelCustomizationTests/CustomCodeReplacesDateNormalizedPropertyUsingRawSpecName/MockInputModel.cs @@ -0,0 +1,14 @@ +#nullable disable + +using Sample; +using SampleTypeSpec; +using Microsoft.TypeSpec.Generator.Customizations; + +namespace Sample.Models +{ + public partial class MockInputModel + { + [CodeGenMember("creationDate")] + public System.DateTimeOffset Created { get; set; } + } +} From 1392c254e189222924a8fa22d44da53bf6362228 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 21 Aug 2026 23:40:41 +0000 Subject: [PATCH 14/14] fix(csharp-generator): resolve CodeGenMember names via identifier casing Co-authored-by: jorgerangel-msft <102122018+jorgerangel-msft@users.noreply.github.com> --- .../src/Providers/CanonicalTypeProvider.cs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/CanonicalTypeProvider.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/CanonicalTypeProvider.cs index 85724f998e0..4020a979bb3 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/CanonicalTypeProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/CanonicalTypeProvider.cs @@ -33,7 +33,6 @@ public CanonicalTypeProvider(TypeProvider generatedTypeProvider, InputType? inpu foreach (var property in _specProperties) { var name = property.IsExactName ? property.Name : property.Name.ToIdentifierName(); - _specPropertiesMap.TryAdd(property.Name, property); _specPropertiesMap.TryAdd(name, property); if (!property.IsExactName) { @@ -189,7 +188,7 @@ protected internal override PropertyProvider[] BuildProperties() { // Check if custom property is in spec if (_specPropertiesMap.TryGetValue(prop.Name, out var specProp) || - (prop.OriginalName != null && _specPropertiesMap.TryGetValue(prop.OriginalName, out specProp))) + (prop.OriginalName != null && TryGetSpecProperty(prop.OriginalName, out specProp))) { inputProperties.Add(specProp); } @@ -291,7 +290,7 @@ private bool TryGetSpecProperty( PropertyProvider customProperty, [NotNullWhen(true)] out InputModelProperty? candidateSpecProperty) { - if (customProperty.OriginalName != null && _specPropertiesMap.TryGetValue(customProperty.OriginalName, out candidateSpecProperty)) + if (customProperty.OriginalName != null && TryGetSpecProperty(customProperty.OriginalName, out candidateSpecProperty)) { return true; } @@ -309,7 +308,7 @@ private bool TryGetSpecProperty( private bool TryGetSpecProperty(FieldProvider customField, [NotNullWhen(true)] out InputModelProperty? candidateSpecProperty) { - if (customField.OriginalName != null && _specPropertiesMap.TryGetValue(customField.OriginalName, out candidateSpecProperty)) + if (customField.OriginalName != null && TryGetSpecProperty(customField.OriginalName, out candidateSpecProperty)) { return true; } @@ -324,6 +323,16 @@ private bool TryGetSpecProperty(FieldProvider customField, [NotNullWhen(true)] o return false; } + private bool TryGetSpecProperty(string name, [NotNullWhen(true)] out InputModelProperty? candidateSpecProperty) + { + if (_specPropertiesMap.TryGetValue(name, out candidateSpecProperty)) + { + return true; + } + + return _specPropertiesMap.TryGetValue(name.ToIdentifierName(), out candidateSpecProperty); + } + private Dictionary BuildSerializationNameMap() { var serializedNameMapping = new Dictionary();