Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose public APIs for Azure plugin to generate ResourceData #5544

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ protected override PropertyProvider[] BuildProperties()
description,
MethodSignatureModifiers.Public,
type,
p.Name.ToCleanName(),
StringHelpers.ToCleanName(p.Name),
new AutoPropertyBody(true),
this));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ private IReadOnlyList<ParameterProvider> GetClientParameters()

protected override string BuildRelativeFilePath() => Path.Combine("src", "Generated", $"{Name}.cs");

protected override string BuildName() => _inputClient.Name.ToCleanName();
protected override string BuildName() => StringHelpers.ToCleanName(_inputClient.Name);

protected override FieldProvider[] BuildFields()
{
Expand Down Expand Up @@ -407,16 +407,16 @@ private MethodBodyStatement[] BuildPrimaryConstructorBody(IReadOnlyList<Paramete

body.Add(PipelineProperty.Assign(This.ToApi<ClientPipelineApi>().Create(ClientOptionsParameter.Value, perRetryPolicies)).Terminate());

var clientOptionsPropertyDict = ClientOptions.Value.Properties.ToDictionary(p => p.Name.ToCleanName());
var clientOptionsPropertyDict = ClientOptions.Value.Properties.ToDictionary(p => StringHelpers.ToCleanName(p.Name));
foreach (var f in Fields)
{
if (f == _apiVersionField && ClientOptions.Value.VersionProperty != null)
{
body.Add(f.Assign(ClientOptionsParameter.Value.Property(ClientOptions.Value.VersionProperty.Name)).Terminate());
}
else if (clientOptionsPropertyDict.TryGetValue(f.Name.ToCleanName(), out var optionsProperty))
else if (clientOptionsPropertyDict.TryGetValue(StringHelpers.ToCleanName(f.Name), out var optionsProperty))
{
clientOptionsPropertyDict.TryGetValue(f.Name.ToCleanName(), out optionsProperty);
clientOptionsPropertyDict.TryGetValue(StringHelpers.ToCleanName(f.Name), out optionsProperty);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
// Licensed under the MIT License.

using System;
using System.ClientModel;
using System.ClientModel.Primitives;
using System.Collections.Generic;
using System.Diagnostics;
Expand All @@ -26,7 +25,7 @@ namespace Microsoft.Generator.CSharp.ClientModel.Providers
/// <summary>
/// This class provides the set of serialization models, methods, and interfaces for a given model.
/// </summary>
internal class MrwSerializationTypeDefinition : TypeProvider
public class MrwSerializationTypeDefinition : TypeProvider
{
private const string JsonModelWriteCoreMethodName = "JsonModelWriteCore";
private const string JsonModelCreateCoreMethodName = "JsonModelCreateCore";
Expand Down Expand Up @@ -88,7 +87,7 @@ public MrwSerializationTypeDefinition(InputModelType inputModel, ModelProvider m

protected override string BuildRelativeFilePath() => Path.Combine("src", "Generated", "Models", $"{Name}.Serialization.cs");

protected override string BuildName() => _inputModel.Name.ToCleanName();
protected override string BuildName() => StringHelpers.ToCleanName(_inputModel.Name);

protected override IReadOnlyList<AttributeStatement> BuildAttributes()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public RestClientProvider(InputClient inputClient, ClientProvider clientProvider

protected override string BuildRelativeFilePath() => Path.Combine("src", "Generated", $"{Name}.RestClient.cs");

protected override string BuildName() => _inputClient.Name.ToCleanName();
protected override string BuildName() => StringHelpers.ToCleanName(_inputClient.Name);

protected override PropertyProvider[] BuildProperties()
{
Expand Down Expand Up @@ -89,7 +89,7 @@ private MethodProvider BuildCreateRequestMethod(InputOperation operation)
var parameters = GetMethodParameters(operation, MethodType.CreateRequest);

var signature = new MethodSignature(
$"Create{operation.Name.ToCleanName()}Request",
$"Create{StringHelpers.ToCleanName(operation.Name)}Request",
null,
MethodSignatureModifiers.Internal,
ClientModelPlugin.Instance.TypeFactory.HttpMessageApi.HttpMessageType,
Expand Down Expand Up @@ -153,7 +153,7 @@ private Dictionary<List<int>, PropertyProvider> BuildPipelineMessage20xClassifie
null,
MethodSignatureModifiers.Private | MethodSignatureModifiers.Static,
ClientModelPlugin.Instance.TypeFactory.StatusCodeClassifierApi.ResponseClassifierType,
classifierBackingField.Name.Substring(1).ToCleanName(),
StringHelpers.ToCleanName(classifierBackingField.Name.Substring(1)),
new ExpressionPropertyBody(
classifierBackingField.Assign(This.ToApi<StatusCodeClassifierApi>().Create(GetSuccessStatusCodes(inputOperation)))),
this)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public class ScmMethodProviderCollection : MethodProviderCollection
public ScmMethodProviderCollection(InputOperation operation, TypeProvider enclosingType)
: base(operation, enclosingType)
{
_cleanOperationName = operation.Name.ToCleanName();
_cleanOperationName = StringHelpers.ToCleanName(operation.Name);
Client = enclosingType as ClientProvider ?? throw new InvalidOperationException("Scm methods can only be built for client types.");
_createRequestMethod = Client.RestClient.GetCreateRequestMethod(Operation);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public void SetUp()
public void ServiceClientWithSubClient()
{
var client = InputFactory.Client(TestClientName);
string[] expectedSubClientFactoryMethodNames = [$"Get{_animalClient.Name.ToCleanName()}Client"];
string[] expectedSubClientFactoryMethodNames = [$"Get{StringHelpers.ToCleanName(_animalClient.Name)}Client"];
var clientProvider = new MockClientProvider(client, expectedSubClientFactoryMethodNames);
var writer = new TypeProviderWriter(clientProvider);
var file = writer.Write();
Expand All @@ -48,7 +48,7 @@ public void ServiceClientWithSubClient()
[Test]
public void SubClientWithSingleSubClient()
{
string[] expectedSubClientFactoryMethodNames = [$"Get{_huskyClient.Name.ToCleanName()}Client"];
string[] expectedSubClientFactoryMethodNames = [$"Get{StringHelpers.ToCleanName(_huskyClient.Name)}Client"];
var clientProvider = new MockClientProvider(_dogClient, expectedSubClientFactoryMethodNames);
var writer = new TypeProviderWriter(clientProvider);
var file = writer.Write();
Expand All @@ -61,9 +61,9 @@ public void SubClientWithMultipleSubClients()
{
string[] expectedSubClientFactoryMethodNames =
[
$"Get{_dogClient.Name.ToCleanName()}Client",
$"Get{_catClient.Name.ToCleanName()}Client",
$"Get{_hawkClient.Name.ToCleanName()}"
$"Get{StringHelpers.ToCleanName(_dogClient.Name)}Client",
$"Get{StringHelpers.ToCleanName(_catClient.Name)}Client",
$"Get{StringHelpers.ToCleanName(_hawkClient.Name)}"
];
var clientProvider = new MockClientProvider(_animalClient, expectedSubClientFactoryMethodNames);
var writer = new TypeProviderWriter(clientProvider);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public void TestBuildDeserializationMethod(
// validate the additional properties variable declarations
for (var i = 0; i < expectedValueTypeNames.Length; i++)
{
var expectedVariableName = i == 0 ? "additionalProperties" : $"additional{expectedValueTypeNames[i].ToCleanName()}Properties";
var expectedVariableName = i == 0 ? "additionalProperties" : $"additional{StringHelpers.ToCleanName(expectedValueTypeNames[i])}Properties";
var expectedDeclaration = $"global::System.Collections.Generic.IDictionary<string, {expectedValueTypeNames[i].ToVariableName()}> {expectedVariableName}";
Assert.IsTrue(methodBodyString.Contains(expectedDeclaration, StringComparison.InvariantCultureIgnoreCase));
}
Expand All @@ -60,7 +60,7 @@ public void TestBuildDeserializationMethod(
if (expectedValueTypeNames.Length > 1)
{
// skip the first value type name as it is already included in the return statement
var additionalPropertiesVariables = "additionalProperties, " + string.Join(", ", expectedValueTypeNames.Skip(1).Select(v => $"additional{v.ToCleanName()}Properties,"));
var additionalPropertiesVariables = "additionalProperties, " + string.Join(", ", expectedValueTypeNames.Skip(1).Select(v => $"additional{StringHelpers.ToCleanName(v)}Properties,"));
var expectedReturnStatement = $"return new global::Sample.Models.Cat(color, {additionalPropertiesVariables} additionalBinaryDataProperties);";
Assert.IsTrue(methodBodyString.Contains(expectedReturnStatement));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -658,7 +658,7 @@ public void TestBuildExplicitFromClientResult()
Assert.IsNotNull(methodSignature);

var expectedModifiers = MethodSignatureModifiers.Public | MethodSignatureModifiers.Static | MethodSignatureModifiers.Explicit | MethodSignatureModifiers.Operator;
Assert.AreEqual(inputModel.Name.ToCleanName(), methodSignature?.Name);
Assert.AreEqual(StringHelpers.ToCleanName(inputModel.Name), methodSignature?.Name);
Assert.AreEqual(expectedModifiers, methodSignature?.Modifiers);

var methodParameters = methodSignature?.Parameters;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public void TestRestClientMethods(InputOperation inputOperation)
var method = restClientProvider.Methods![0];
var signature = method.Signature;
Assert.IsNotNull(signature);
Assert.AreEqual($"Create{inputOperation.Name.ToCleanName()}Request", signature.Name);
Assert.AreEqual($"Create{StringHelpers.ToCleanName(inputOperation.Name)}Request", signature.Name);

var parameters = signature.Parameters;
Assert.IsNotNull(parameters);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,15 @@ public void TestDefaultCSharpMethodCollection(InputOperation inputOperation)
var method = methodCollection![0];
var signature = method.Signature;
Assert.IsNotNull(signature);
Assert.AreEqual(inputOperation.Name.ToCleanName(), signature.Name);
Assert.AreEqual(StringHelpers.ToCleanName(inputOperation.Name), signature.Name);

var parameters = signature.Parameters;
Assert.IsNotNull(parameters);
Assert.AreEqual(inputOperation.Parameters.Count + 1, parameters.Count);

var convenienceMethod = methodCollection.FirstOrDefault(m
=> !m.Signature.Parameters.Any(p => p.Name == "content")
&& m.Signature.Name == $"{inputOperation.Name.ToCleanName()}");
&& m.Signature.Name == $"{StringHelpers.ToCleanName(inputOperation.Name)}");
Assert.IsNotNull(convenienceMethod);

var convenienceMethodParams = convenienceMethod!.Signature.Parameters;
Expand Down Expand Up @@ -78,7 +78,7 @@ public void ConvenienceMethodsHaveOptionalCancellationToken(InputOperation input

var asyncConvenienceMethod = methodCollection.FirstOrDefault(m
=> !m.Signature.Parameters.Any(p => p.Name == "content")
&& m.Signature.Name == $"{inputOperation.Name.ToCleanName()}Async");
&& m.Signature.Name == $"{StringHelpers.ToCleanName(inputOperation.Name)}Async");
Assert.IsNotNull(asyncConvenienceMethod);

var asyncConvenienceMethodParameters = asyncConvenienceMethod!.Signature.Parameters;
Expand All @@ -91,7 +91,7 @@ public void ConvenienceMethodsHaveOptionalCancellationToken(InputOperation input

var syncConvenienceMethod = methodCollection.FirstOrDefault(m
=> !m.Signature.Parameters.Any(p => p.Name == "content")
&& m.Signature.Name == inputOperation.Name.ToCleanName());
&& m.Signature.Name == StringHelpers.ToCleanName(inputOperation.Name));
Assert.IsNotNull(syncConvenienceMethod);

var syncConvenienceMethodParameters = syncConvenienceMethod!.Signature.Parameters;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ internal set

_discriminatedSubtypes = new Dictionary<string, InputModelType>(value);

var cleanBaseName = Name.ToCleanName();
var cleanBaseName = StringHelpers.ToCleanName(Name);
_discriminatedSubtypes.Add(UnknownDiscriminatorValue,
new InputModelType(
$"Unknown{cleanBaseName}",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System.Diagnostics.CodeAnalysis;
using System.Text;
using Microsoft.CodeAnalysis.CSharp;

namespace Microsoft.Generator.CSharp.Input
{
public static class StringHelpers
{
private static bool IsWordSeparator(char c) => !SyntaxFacts.IsIdentifierPartCharacter(c) || c == '_';

[return: NotNullIfNotNull("name")]
public static string ToCleanName(string name, bool isCamelCase = true)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is moved from original StringExtensinos.ToCleanName.
Synced with @JoshLove-msft before, we should not expose public extension methods for BCL types, turn them into static methods intead.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still not convinced that we need to make this public - https://github.com/Azure/azure-sdk-for-net/pull/47730/files#r1909256494

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK. Revert it again.

{
if (string.IsNullOrEmpty(name))
{
return name;
}
StringBuilder nameBuilder = new StringBuilder();

int i = 0;

if (char.IsDigit(name[0]))
{
nameBuilder.Append("_");
}
else
{
while (!SyntaxFacts.IsIdentifierStartCharacter(name[i]))
{
i++;
}
}

bool upperCase = false;
int firstWordLength = 1;
for (; i < name.Length; i++)
{
var c = name[i];
if (IsWordSeparator(c))
{
upperCase = true;
continue;
}

if (nameBuilder.Length == 0 && isCamelCase)
{
c = char.ToUpper(c);
upperCase = false;
}
else if (nameBuilder.Length < firstWordLength && !isCamelCase)
{
c = char.ToLower(c);
upperCase = false;
// grow the first word length when this letter follows by two other upper case letters
// this happens in OSProfile, where OS is the first word
if (i + 2 < name.Length && char.IsUpper(name[i + 1]) && (char.IsUpper(name[i + 2]) || IsWordSeparator(name[i + 2])))
firstWordLength++;
// grow the first word length when this letter follows by another upper case letter and an end of the string
// this happens when the string only has one word, like OS, DNS
if (i + 2 == name.Length && char.IsUpper(name[i + 1]))
firstWordLength++;
}

if (upperCase)
{
c = char.ToUpper(c);
upperCase = false;
}

nameBuilder.Append(c);
}

return nameBuilder.ToString();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public CanonicalTypeProvider(TypeProvider generatedTypeProvider, InputType? inpu
_generatedTypeProvider = generatedTypeProvider;
var inputModel = inputType as InputModelType;
var specProperties = inputModel?.Properties ?? [];
_specPropertiesMap = specProperties.ToDictionary(p => p.Name.ToCleanName(), p => p);
_specPropertiesMap = specProperties.ToDictionary(p => StringHelpers.ToCleanName(p.Name), p => p);
_serializedNameMap = BuildSerializationNameMap();
_renamedProperties = (_generatedTypeProvider.CustomCodeView?.Properties ?? [])
.Where(p => p.OriginalName != null).Select(p => p.OriginalName!).ToHashSet();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ protected EnumProvider(InputEnumType input)

protected override string BuildRelativeFilePath() => Path.Combine("src", "Generated", "Models", $"{Name}.cs");

protected override string BuildName() => _inputType.Name.ToCleanName();
protected override string BuildName() => StringHelpers.ToCleanName(_inputType.Name);
protected override FormattableString Description { get; }

protected override TypeProvider[] BuildSerializationProviders()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ protected override IReadOnlyList<EnumTypeMember> BuildEnumValues()
// build the field
var modifiers = FieldModifiers.Private | FieldModifiers.Const;
// the fields for extensible enums are private and const, storing the underlying values, therefore we need to append the word `Value` to the name
var valueName = inputValue.Name.ToCleanName();
var valueName = StringHelpers.ToCleanName(inputValue.Name);
var name = $"{valueName}Value";
// for initializationValue, if the enum is extensible, we always need it
var initializationValue = Literal(inputValue.Value);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
using Microsoft.Generator.CSharp.Expressions;
using Microsoft.Generator.CSharp.Input;
using Microsoft.Generator.CSharp.Primitives;
using Microsoft.Generator.CSharp.SourceInput;
using Microsoft.Generator.CSharp.Utilities;
using static Microsoft.Generator.CSharp.Snippets.Snippet;

Expand Down Expand Up @@ -66,7 +65,7 @@ protected override IReadOnlyList<EnumTypeMember> BuildEnumValues()
// the fields for fixed enums are just its members (we use fields to represent the values in a system `enum` type), we just use the name for this field
var name = _isApiVersionEnum
? inputValue.Name.ToApiVersionMemberName()
: inputValue.Name.ToCleanName();
: StringHelpers.ToCleanName(inputValue.Name);

// check if the enum member was renamed in custom code
string? customMemberName = null;
Expand Down
Loading
Loading