Skip to content

Commit 12fffea

Browse files
authored
Fix property name for safe flatten (#51751)
1 parent b52faaf commit 12fffea

File tree

10 files changed

+137
-38
lines changed

10 files changed

+137
-38
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
using Humanizer;
5+
using System.Collections.Generic;
6+
using System.Linq;
7+
8+
namespace Azure.Generator.Management.Extensions
9+
{
10+
internal static class StringExtensions
11+
{
12+
public static IEnumerable<string> SplitByCamelCase(this string camelCase)
13+
{
14+
return camelCase.Humanize().Split(' ').Select(w => w.FirstCharToUpperCase());
15+
}
16+
17+
public static string FirstCharToUpperCase(this string str)
18+
{
19+
if (string.IsNullOrEmpty(str) || char.IsUpper(str[0]))
20+
return str;
21+
22+
return char.ToUpper(str[0]) + str.Substring(1);
23+
}
24+
}
25+
}

eng/packages/http-client-csharp-mgmt/generator/Azure.Generator.Management/src/ManagementClientGenerator.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,14 +50,15 @@ protected override void Configure()
5050
base.Configure();
5151
// Include Azure.ResourceManager
5252
AddMetadataReference(MetadataReference.CreateFromFile(typeof(ArmClient).Assembly.Location));
53+
// renaming should come first
54+
AddVisitor(new NameVisitor());
55+
AddVisitor(new SerializationVisitor());
56+
AddVisitor(new SafeFlattenVisitor());
5357
AddVisitor(new RestClientVisitor());
5458
AddVisitor(new ResourceVisitor());
5559
AddVisitor(new SystemObjectModelVisitor());
56-
AddVisitor(new NameVisitor());
5760
AddVisitor(new TypeFilterVisitor());
58-
AddVisitor(new SerializationVisitor());
5961
AddVisitor(new PaginationVisitor());
60-
AddVisitor(new SafeFlattenVisitor());
6162
AddVisitor(new ModelFactoryVisitor());
6263
}
6364
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
using Azure.Generator.Management.Extensions;
5+
using Humanizer;
6+
using Microsoft.TypeSpec.Generator.Providers;
7+
using System;
8+
using System.Collections.Generic;
9+
using System.Linq;
10+
11+
namespace Azure.Generator.Management.Utilities
12+
{
13+
internal class PropertyHelpers
14+
{
15+
public static string GetCombinedPropertyName(PropertyProvider innerProperty, PropertyProvider immediateParentProperty)
16+
{
17+
var immediateParentPropertyName = GetPropertyName(immediateParentProperty);
18+
19+
if (innerProperty.Type.Equals(typeof(bool)) || innerProperty.Type.Equals(typeof(bool?)))
20+
{
21+
return innerProperty.Name.Equals("Enabled", StringComparison.Ordinal) ? $"{immediateParentPropertyName}{innerProperty.Name}" : innerProperty.Name;
22+
}
23+
24+
if (innerProperty.Name.Equals("Id", StringComparison.Ordinal))
25+
return $"{immediateParentPropertyName}{innerProperty.Name}";
26+
27+
if (immediateParentPropertyName.EndsWith(innerProperty.Name, StringComparison.Ordinal))
28+
return immediateParentPropertyName;
29+
30+
var parentWords = immediateParentPropertyName.SplitByCamelCase();
31+
if (immediateParentPropertyName.EndsWith("Profile", StringComparison.Ordinal) ||
32+
immediateParentPropertyName.EndsWith("Policy", StringComparison.Ordinal) ||
33+
immediateParentPropertyName.EndsWith("Configuration", StringComparison.Ordinal) ||
34+
immediateParentPropertyName.EndsWith("Properties", StringComparison.Ordinal) ||
35+
immediateParentPropertyName.EndsWith("Settings", StringComparison.Ordinal))
36+
{
37+
parentWords = parentWords.Take(parentWords.Count() - 1);
38+
}
39+
40+
var parentWordArray = parentWords.ToArray();
41+
var parentWordsHash = new HashSet<string>(parentWordArray);
42+
var nameWords = innerProperty.Name.SplitByCamelCase().ToArray();
43+
var lastWord = string.Empty;
44+
for (int i = 0; i < nameWords.Length; i++)
45+
{
46+
var word = nameWords[i];
47+
lastWord = word;
48+
if (parentWordsHash.Contains(word))
49+
{
50+
if (i == nameWords.Length - 2 && parentWordArray.Length >= 2 && word.Equals(parentWordArray[parentWordArray.Length - 2], StringComparison.Ordinal))
51+
{
52+
parentWords = parentWords.Take(parentWords.Count() - 2);
53+
break;
54+
}
55+
{
56+
return innerProperty.Name;
57+
}
58+
}
59+
60+
//need to depluralize the last word and check
61+
if (i == nameWords.Length - 1 && parentWordsHash.Contains(lastWord.Pluralize()))
62+
return innerProperty.Name;
63+
}
64+
65+
immediateParentPropertyName = string.Join("", parentWords);
66+
67+
return $"{immediateParentPropertyName}{innerProperty.Name}";
68+
}
69+
70+
private static string GetPropertyName(PropertyProvider property)
71+
{
72+
const string properties = "Properties";
73+
if (property.Name.Equals(properties, StringComparison.Ordinal))
74+
{
75+
string typeName = property.Type.Name;
76+
int index = typeName.IndexOf(properties);
77+
if (index > -1 && index + properties.Length == typeName.Length)
78+
return typeName.Substring(0, index);
79+
80+
return typeName;
81+
}
82+
return property.Name;
83+
}
84+
}
85+
}

eng/packages/http-client-csharp-mgmt/generator/Azure.Generator.Management/src/Visitors/NameVisitor.cs

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -74,23 +74,20 @@ internal class NameVisitor : ScmLibraryVisitor
7474

7575
if (TryTransformUrlToUri(model.Name, out var newName))
7676
{
77-
UpdateConstructors(type, newName);
7877
UpdateSerialization(type, newName, type.Name);
7978
type.Update(name: newName);
8079
}
8180

8281
if (_knownTypes.Contains(model.Name))
8382
{
8483
newName = $"{ManagementClientGenerator.Instance.TypeFactory.ResourceProviderName}{model.Name}";
85-
UpdateConstructors(type, newName);
8684
UpdateSerialization(type, newName, type.Name);
8785
type.Update(name: newName);
8886
}
8987

9088
if (inputLibrary.TryFindEnclosingResourceNameForResourceUpdateModel(model, out var enclosingResourceName))
9189
{
9290
newName = $"{enclosingResourceName}Patch";
93-
UpdateConstructors(type, newName);
9491
UpdateSerialization(type, newName, type.Name);
9592
type.Update(name: newName);
9693

@@ -103,16 +100,6 @@ internal class NameVisitor : ScmLibraryVisitor
103100
return base.PreVisitModel(model, type);
104101
}
105102

106-
// TODO: we will remove this manual updated when https://github.com/microsoft/typespec/issues/8079 is resolved
107-
private static void UpdateConstructors(ModelProvider type, string newName)
108-
{
109-
foreach (var constructor in type.Constructors)
110-
{
111-
// Update the constructor name to match the model name
112-
constructor.Signature.Update(name: newName);
113-
}
114-
}
115-
116103
// TODO: we will remove this manual updated when https://github.com/microsoft/typespec/issues/8079 is resolved
117104
private void UpdateSerialization(ModelProvider type, string newName, string originalName)
118105
{

eng/packages/http-client-csharp-mgmt/generator/Azure.Generator.Management/src/Visitors/SafeFlattenVisitor.cs

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Copyright (c) Microsoft Corporation. All rights reserved.
22
// Licensed under the MIT License.
33

4+
using Azure.Generator.Management.Utilities;
45
using Microsoft.TypeSpec.Generator.ClientModel;
56
using Microsoft.TypeSpec.Generator.Expressions;
67
using Microsoft.TypeSpec.Generator.Input;
@@ -40,22 +41,22 @@ internal class SafeFlattenVisitor : ScmLibraryVisitor
4041
var propertyTypeProvider = ManagementClientGenerator.Instance.TypeFactory.CreateModel(propertyModelType)!;
4142
if (propertyTypeProvider.Properties.Count == 1)
4243
{
43-
var singleProperty = propertyTypeProvider.Properties.Single();
44+
var innerProperty = propertyTypeProvider.Properties.Single();
4445

4546
// make the current property internal
46-
var internalProperty = type!.Properties.Single(p => p.Type.AreNamesEqual(propertyTypeProvider.Type)); // type equal not working here, so we use AreNamesEqual
47-
internalizedProperties.Add(internalProperty);
47+
var immediateParentProperty = type!.Properties.Single(p => p.Type.AreNamesEqual(propertyTypeProvider.Type)); // type equal not working here, so we use AreNamesEqual
48+
internalizedProperties.Add(immediateParentProperty);
4849

4950
// flatten the single property to public and associate it with the internal property
50-
var (isFlattenedPropertyReadOnly, includeGetterNullCheck, includeSetterNullCheck) = GetFlags(property.IsReadOnly, singleProperty, propertyTypeProvider, propertyTypeProvider);
51-
var flattenPropertyName = $"{internalProperty.Name}{singleProperty.Name}"; // TODO: handle name conflicts
51+
var (isFlattenedPropertyReadOnly, includeGetterNullCheck, includeSetterNullCheck) = GetFlags(property.IsReadOnly, innerProperty, propertyTypeProvider, propertyTypeProvider);
52+
var flattenPropertyName = PropertyHelpers.GetCombinedPropertyName(innerProperty, immediateParentProperty); // TODO: handle name conflicts
5253
var flattenPropertyBody = new MethodPropertyBody(
53-
BuildGetter(includeGetterNullCheck, internalProperty, propertyTypeProvider, singleProperty),
54-
isFlattenedPropertyReadOnly ? null : BuildSetter(includeSetterNullCheck, propertyTypeProvider, internalProperty, singleProperty)
54+
BuildGetter(includeGetterNullCheck, immediateParentProperty, propertyTypeProvider, innerProperty),
55+
isFlattenedPropertyReadOnly ? null : BuildSetter(includeSetterNullCheck, propertyTypeProvider, immediateParentProperty, innerProperty)
5556
);
56-
var flattenedProperty = new PropertyProvider(singleProperty.Description, singleProperty.Modifiers, singleProperty.Type, flattenPropertyName, flattenPropertyBody, type, singleProperty.ExplicitInterface, singleProperty.WireInfo, singleProperty.Attributes);
57+
var flattenedProperty = new PropertyProvider(innerProperty.Description, innerProperty.Modifiers, innerProperty.Type, flattenPropertyName, flattenPropertyBody, type, innerProperty.ExplicitInterface, innerProperty.WireInfo, innerProperty.Attributes);
5758
flattenedProperties.Add(flattenedProperty);
58-
flattenedPropertyMap.Add(internalProperty.Type, flattenedProperty);
59+
flattenedPropertyMap.Add(immediateParentProperty.Type, flattenedProperty);
5960
}
6061
}
6162
}

eng/packages/http-client-csharp-mgmt/generator/TestProjects/Local/Mgmt-TypeSpec/src/Generated/BarSettingsData.cs

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

eng/packages/http-client-csharp-mgmt/generator/TestProjects/Local/Mgmt-TypeSpec/src/Generated/MgmtTypeSpecModelFactory.cs

Lines changed: 9 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

eng/packages/http-client-csharp-mgmt/generator/TestProjects/Local/Mgmt-TypeSpec/src/Generated/Models/FooSettingsPatch.cs

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

eng/packages/http-client-csharp-mgmt/generator/TestProjects/Local/Mgmt-TypeSpec/src/Generated/Models/ZooPatch.cs

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

eng/packages/http-client-csharp-mgmt/generator/TestProjects/Local/Mgmt-TypeSpec/src/Generated/ZooData.cs

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)