diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Primitives/ScmKnownParameters.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Primitives/ScmKnownParameters.cs index a9125f412a2..7517c525ac0 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Primitives/ScmKnownParameters.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Primitives/ScmKnownParameters.cs @@ -30,13 +30,21 @@ internal static class ScmKnownParameters public static readonly ParameterProvider Data = new("data", FormattableStringHelpers.Empty, typeof(BinaryData)); public static ParameterProvider ClientOptions(CSharpType clientOptionsType) => new("options", $"The options for configuring the client.", clientOptionsType, initializationValue: New.Instance(clientOptionsType)); - public static readonly ParameterProvider OptionalRequestOptions = new( + public static readonly ParameterProvider OptionalRequestOptions = CreateRequestOptions(optional: true); + public static readonly ParameterProvider RequestOptions = CreateRequestOptions(); + public static readonly ParameterProvider CancellationToken = CreateCancellationToken(); + + public static ParameterProvider CreateRequestOptions(bool optional = false) => new( ScmCodeModelGenerator.Instance.TypeFactory.HttpRequestOptionsApi.ParameterName, $"The request options, which can override default behaviors of the client pipeline on a per-call basis.", ScmCodeModelGenerator.Instance.TypeFactory.HttpRequestOptionsApi.HttpRequestOptionsType, - defaultValue: Null); - public static readonly ParameterProvider RequestOptions = new(ScmCodeModelGenerator.Instance.TypeFactory.HttpRequestOptionsApi.ParameterName, $"The request options, which can override default behaviors of the client pipeline on a per-call basis.", ScmCodeModelGenerator.Instance.TypeFactory.HttpRequestOptionsApi.HttpRequestOptionsType); - public static readonly ParameterProvider CancellationToken = new("cancellationToken", $"The cancellation token that can be used to cancel the operation.", new CSharpType(typeof(CancellationToken)), defaultValue: Default); + defaultValue: optional ? Null : null); + + public static ParameterProvider CreateCancellationToken() => new( + "cancellationToken", + $"The cancellation token that can be used to cancel the operation.", + new CSharpType(typeof(CancellationToken)), + defaultValue: Default); private static readonly FormattableString RequestContentDescription = $"The content to send as the body of the request."; private const string RequestContentParameterName = "content"; @@ -66,20 +74,15 @@ public static ParameterProvider ClientOptions(CSharpType clientOptionsType) private static readonly FormattableString ContentTypeDescription = $"The contentType to use which has the multipart/form-data boundary."; private static readonly PropertyWireInformation ContentTypeWireInfo = new(SerializationFormat.Default, true, false, false, false, "Content-Type", false, false); - public static readonly ParameterProvider ContentType = new( - ContentTypeParameterName, - ContentTypeDescription, - typeof(string), - wireInfo: ContentTypeWireInfo) - { - Validation = ParameterValidationType.AssertNotNullOrEmpty, - }; + public static readonly ParameterProvider ContentType = CreateContentType(isRequired: true); + public static readonly ParameterProvider OptionalContentType = CreateContentType(isRequired: false); - public static readonly ParameterProvider OptionalContentType = new( + public static ParameterProvider CreateContentType(bool isRequired) => new( ContentTypeParameterName, ContentTypeDescription, typeof(string), - wireInfo: ContentTypeWireInfo); + wireInfo: ContentTypeWireInfo, + validation: isRequired ? ParameterValidationType.AssertNotNullOrEmpty : ParameterValidationType.None); public static readonly ParameterProvider NextPage = new ParameterProvider("nextPage", $"The url of the next page of responses.", typeof(Uri)); diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ClientProvider.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ClientProvider.cs index e0d562963d4..9f5e3c16ae0 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ClientProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ClientProvider.cs @@ -1489,7 +1489,7 @@ protected sealed override IReadOnlyList BuildMethodsForBackCompa foreach (var (method, originalSignature) in originalSignatures) { if (method.Signature.Name.Equals(originalSignature.Name) - && !MethodSignatureHelper.HaveSameParametersInSameOrder(method.Signature, originalSignature)) + && !method.Signature.Parameters.SequenceEqual(originalSignature.Parameters, ReferenceEqualityComparer.Instance)) { updatedSignatureToOriginal.TryAdd(method.Signature, originalSignature); methodsWithReorderedParams.Add(method); @@ -1860,7 +1860,7 @@ private static void ReorderMethodInvocationArguments( MethodSignature updatedSignature) { var argumentCount = invocation.Arguments.Count; - if (argumentCount != originalSignature.Parameters.Count) + if (argumentCount > originalSignature.Parameters.Count) { return; } @@ -1868,15 +1868,26 @@ private static void ReorderMethodInvocationArguments( var argumentsByName = new Dictionary(argumentCount); for (int i = 0; i < argumentCount; i++) { - argumentsByName.TryAdd(originalSignature.Parameters[i].Name, invocation.Arguments[i]); + var argument = invocation.Arguments[i]; + var parameterName = argument is PositionalParameterReferenceExpression named + ? named.ParameterName + : originalSignature.Parameters[i].Name; + argumentsByName.Add(parameterName, argument); } var reorderedArgs = new List(updatedSignature.Parameters.Count); + bool requireNamedArgs = false; foreach (var param in updatedSignature.Parameters) { if (argumentsByName.TryGetValue(param.Name, out var arg)) { - reorderedArgs.Add(arg); + reorderedArgs.Add(requireNamedArgs && arg is not PositionalParameterReferenceExpression + ? param.PositionalReference(arg) + : arg); + } + else + { + requireNamedArgs = true; } } diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/RestClientProvider.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/RestClientProvider.cs index 7a51a07801d..b276ec49d2d 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/RestClientProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/RestClientProvider.cs @@ -192,7 +192,7 @@ protected override ScmMethodProvider[] BuildMethods() private ScmMethodProvider BuildCreateRequestMethod(InputServiceMethod serviceMethod, bool isNextLinkRequest = false) { - var options = ScmKnownParameters.RequestOptions; + var options = ScmKnownParameters.CreateRequestOptions(); var parameters = GetMethodParameters(serviceMethod, ScmMethodKind.CreateRequest, ClientProvider); if (isNextLinkRequest) @@ -266,7 +266,7 @@ private MethodBodyStatements BuildMessage( { // Create required components var pipelineField = ClientProvider.PipelineProperty.ToApi(); - var options = ScmKnownParameters.RequestOptions; + var options = signature.Parameters[^1]; var operation = serviceMethod.Operation; var classifier = GetClassifier(operation); @@ -1417,7 +1417,7 @@ internal static List GetMethodParameters( { bool bodyIsRequired = methodType == ScmMethodKind.Protocol && operation.Parameters.OfType().Any(p => p.IsRequired); - sortedParams.Add(contentType++, bodyIsRequired ? ScmKnownParameters.ContentType : ScmKnownParameters.OptionalContentType); + sortedParams.Add(contentType++, ScmKnownParameters.CreateContentType(bodyIsRequired)); } if (methodType == ScmMethodKind.CreateRequest) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ScmMethodProviderCollection.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ScmMethodProviderCollection.cs index ee24dd71af6..37aca252828 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ScmMethodProviderCollection.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/ScmMethodProviderCollection.cs @@ -35,11 +35,6 @@ public class ScmMethodProviderCollection : IReadOnlyList private static readonly CancellationTokenExtensionsDefinition _cancellationTokenExtensionsDefinition = new(); private const string JsonMediaType = "application/json"; private const string XmlMediaType = "application/xml"; - private IList ProtocolMethodParameters => _protocolMethodParameters ??= RestClientProvider.GetMethodParameters(ServiceMethod, ScmMethodKind.Protocol, Client); - private IList? _protocolMethodParameters; - - private IReadOnlyList ConvenienceMethodParameters => _convenienceMethodParameters ??= RestClientProvider.GetMethodParameters(ServiceMethod, ScmMethodKind.Convenience, Client); - private IReadOnlyList? _convenienceMethodParameters; private readonly InputPagingServiceMethod? _pagingServiceMethod; private IReadOnlyList? _methods; private readonly bool _generateConvenienceMethod; @@ -171,7 +166,8 @@ private ScmMethodProvider BuildConvenienceMethod(MethodProvider protocolMethod, } var methodName = isAsync ? ServiceMethod.Name + "Async" : ServiceMethod.Name; - ParameterProvider[] signatureParameters = [.. ConvenienceMethodParameters, ScmKnownParameters.CancellationToken]; + var convenienceParameters = RestClientProvider.GetMethodParameters(ServiceMethod, ScmMethodKind.Convenience, Client); + ParameterProvider[] signatureParameters = [.. convenienceParameters, ScmKnownParameters.CreateCancellationToken()]; // Detect a partial method declaration in the client's custom code matching this convenience method. MethodSignature? customSignature = null; @@ -192,8 +188,8 @@ private ScmMethodProvider BuildConvenienceMethod(MethodProvider protocolMethod, removeDefaults: true); // The generator-controlled body params are the leading parameters (everything except the trailing CancellationToken). - var bodyParams = new ParameterProvider[ConvenienceMethodParameters.Count]; - for (int i = 0; i < ConvenienceMethodParameters.Count; i++) + var bodyParams = new ParameterProvider[convenienceParameters.Count]; + for (int i = 0; i < convenienceParameters.Count; i++) { bodyParams[i] = renamedSignatureParameters[i]; } @@ -208,7 +204,7 @@ private ScmMethodProvider BuildConvenienceMethod(MethodProvider protocolMethod, } else { - convenienceBodyParameters = ConvenienceMethodParameters; + convenienceBodyParameters = signatureParameters[..^1]; methodSignature = new MethodSignature( methodName, DocHelpers.GetFormattableDescription(ServiceMethod.Operation.Summary, ServiceMethod.Operation.Doc) ?? FormattableStringHelpers.FromString(ServiceMethod.Operation.Name), @@ -237,7 +233,7 @@ .. GetPagingMethodBody( createRequestSignature, convenienceBodyParameters, true, - [.. protocolMethod.Signature.Parameters]) + methodSignature.Parameters[^1]) ]; } else if (streamingResponse != null) @@ -245,7 +241,7 @@ .. GetPagingMethodBody( var conversionStatements = GetStackVariablesForProtocolParamConversion( convenienceBodyParameters, out var declarations); - var protocolArguments = GetProtocolMethodArguments(declarations); + var protocolArguments = GetMethodArguments(_createRequestMethod.Signature, declarations, convenienceBodyParameters, methodSignature.Parameters[^1]); var requestOptions = protocolArguments[^1]; methodBody = [ @@ -262,7 +258,7 @@ .. GetPagingMethodBody( message, requestOptions.ToApi(), true), - signatureParameters[^1], + methodSignature.Parameters[^1], useConvenienceType: true)) ]; } @@ -271,7 +267,7 @@ .. GetPagingMethodBody( methodBody = [ .. GetStackVariablesForProtocolParamConversion(convenienceBodyParameters, out var declarations), - Return(This.Invoke(protocolMethod.Signature, [.. GetProtocolMethodArguments(declarations)], isAsync)) + Return(This.Invoke(protocolMethod.Signature, [.. GetMethodArguments(protocolMethod.Signature, declarations, convenienceBodyParameters, methodSignature.Parameters[^1])], isAsync)) ]; } else @@ -279,7 +275,7 @@ .. GetStackVariablesForProtocolParamConversion(convenienceBodyParameters, out va methodBody = [ .. GetStackVariablesForProtocolParamConversion(convenienceBodyParameters, out var paramDeclarations), - Declare("result", This.Invoke(protocolMethod.Signature, [.. GetProtocolMethodArguments(paramDeclarations)], isAsync).ToApi(), out ClientResponseApi result), + Declare("result", This.Invoke(protocolMethod.Signature, [.. GetMethodArguments(protocolMethod.Signature, paramDeclarations, convenienceBodyParameters, methodSignature.Parameters[^1])], isAsync).ToApi(), out ClientResponseApi result), .. GetStackVariablesForReturnValueConversion(result, responseBodyType, isAsync, out var resultDeclarations), IsConvertibleFromBinaryData(responseBodyType) || GetPlainTextParseType(responseBodyType, out _) is not null @@ -474,20 +470,20 @@ void AddUtf8JsonContent(CSharpType serializationType, ValueExpression value) var spreadSource = convenienceMethodParameters.FirstOrDefault(p => p.SpreadSource != null)?.SpreadSource; if (spreadSource is not null) { - statements.Add(Declare("spreadModel", New.Instance(spreadSource.Type, [.. GetSpreadConversion(spreadSource)]).As(spreadSource.Type), out var spread)); + statements.Add(Declare("spreadModel", New.Instance(spreadSource.Type, [.. GetSpreadConversion(spreadSource, convenienceMethodParameters)]).As(spreadSource.Type), out var spread)); declarations["spread"] = spread; } return statements; } - private List GetSpreadConversion(TypeProvider spreadSource) + private List GetSpreadConversion(TypeProvider spreadSource, IReadOnlyList convenienceMethodParameters) { // Match convenience method parameters to constructor parameters by wire (serialized) name // to handle cases where C# names diverge due to @clientName renames, @encodedName, // or casing differences between the convenience parameters and model properties. var convenienceMethodParamsByWireName = new Dictionary(StringComparer.OrdinalIgnoreCase); - foreach (var p in ConvenienceMethodParameters) + foreach (var p in convenienceMethodParameters) { if (p.WireInfo?.SerializedName != null) { @@ -501,7 +497,7 @@ private List GetSpreadConversion(TypeProvider spreadSource) { if (property.OriginalName != null && property.WireInfo?.SerializedName is { } wireName) { - var matchedParam = ConvenienceMethodParameters.FirstOrDefault( + var matchedParam = convenienceMethodParameters.FirstOrDefault( p => string.Equals(p.WireInfo?.SerializedName, wireName, StringComparison.OrdinalIgnoreCase)); if (matchedParam != null) { @@ -1154,10 +1150,15 @@ private static void ApplyExperimentalAttributes( } } - private IReadOnlyList GetProtocolMethodArguments(Dictionary declarations) + private IReadOnlyList GetMethodArguments( + MethodSignature signature, + Dictionary declarations, + IReadOnlyList convenienceMethodParameters, + ParameterProvider cancellationToken) { - List conversions = new List(); + List conversions = []; bool addedSpreadSource = false; + var requestOptionsParameter = signature.Parameters[^1]; ModelProvider? bodyModel = null; InputParameter? methodBodyParameter = ServiceMethod.Parameters.FirstOrDefault(p => p.Location == InputRequestLocation.Body); @@ -1166,17 +1167,17 @@ private IReadOnlyList GetProtocolMethodArguments(Dictionary p.Location == ParameterLocation.Body); + var bodyParamProvider = convenienceMethodParameters.FirstOrDefault(p => p.Location == ParameterLocation.Body); var nonBodyProperties = bodyModel?.CanonicalView.Properties .Where(p => p.WireInfo?.IsHttpMetadata == true) .ToDictionary(p => p.WireInfo!.SerializedName, p => p); - // Create a mapping from convenience parameter names to their ParameterProvider - var convenienceParamsMap = ConvenienceMethodParameters.ToDictionary(p => p.Name, p => p, StringComparer.OrdinalIgnoreCase); + var convenienceParamsMap = convenienceMethodParameters.ToDictionary( + parameter => parameter.InputParameter?.Name ?? parameter.WireInfo.SerializedName, + StringComparer.OrdinalIgnoreCase); bool requireNamedArgs = false; - // Iterate through protocol parameters to maintain correct argument order - foreach (var protocolParam in ProtocolMethodParameters) + foreach (var protocolParam in signature.Parameters) { // Skip RequestOptions parameter as it's added at the end if (protocolParam.Type.Equals(ScmCodeModelGenerator.Instance.TypeFactory.HttpRequestOptionsApi.HttpRequestOptionsType)) @@ -1235,7 +1236,8 @@ private IReadOnlyList GetProtocolMethodArguments(Dictionary GetProtocolMethodArguments(Dictionary GetProtocolMethodArguments(Dictionary(); var optionalParameters = new List(); + var convertedRequiredParameters = new List(); + var protocolParameters = RestClientProvider.GetMethodParameters(ServiceMethod, ScmMethodKind.Protocol, Client); + var contentIndex = protocolParameters.FindIndex(parameter => parameter.IsContentParameter); + var hasOptionalContent = contentIndex >= 0 && protocolParameters[contentIndex].DefaultValue != null; + var makeOptionalRequired = shouldMakeParametersRequired + && (contentIndex < 0 || hasOptionalContent); + int requiredBeforeContent = 0; - for (var i = 0; i < ProtocolMethodParameters.Count; i++) + for (var i = 0; i < protocolParameters.Count; i++) { - var parameter = ProtocolMethodParameters[i]; + if (i == contentIndex) + { + requiredBeforeContent = requiredParameters.Count; + } + var parameter = protocolParameters[i]; + if (makeOptionalRequired && parameter.DefaultValue != null && (contentIndex < 0 || i <= contentIndex)) + { + // Keep the optional source unchanged when constructing the required-nullable protocol variant. + parameter = parameter.IsContentParameter + ? ScmKnownParameters.CreateRequestContent(parameter.InputParameter, nullable: true) + : new ParameterProvider( + parameter.Name, + parameter.Description, + parameter.Type.WithNullable(true), + isRef: parameter.IsRef, + isOut: parameter.IsOut, + isIn: parameter.IsIn, + isParams: parameter.IsParams, + attributes: parameter.Attributes, + property: parameter.Property, + field: parameter.Field, + initializationValue: parameter.InitializationValue, + location: parameter.Location, + wireInfo: parameter.WireInfo, + validation: parameter.Validation, + inputParameter: parameter.InputParameter) + { + SpreadSource = parameter.SpreadSource + }; + convertedRequiredParameters.Add(parameter); + continue; + } if (parameter.DefaultValue is null) { requiredParameters.Add(parameter); @@ -1401,16 +1441,12 @@ private ScmMethodProvider BuildProtocolMethod(MethodProvider createRequestMethod optionalParameters.Add(parameter); } } - ParameterProvider requestOptionsParameter = ScmKnownParameters.RequestOptions; - - if (shouldMakeParametersRequired) - { - ProcessOptionalParameters(optionalParameters, requiredParameters, ref requestOptionsParameter); - } - else - { - requestOptionsParameter = ScmKnownParameters.OptionalRequestOptions; - } + // Converted body parameters stay ahead of trailing required headers. + requiredParameters.InsertRange( + hasOptionalContent ? requiredBeforeContent : requiredParameters.Count, + convertedRequiredParameters); + var requestOptionsParameter = ScmKnownParameters.CreateRequestOptions( + optional: !shouldMakeParametersRequired || contentIndex >= 0); // A grouped options bag adopted by the protocol method can carry the same name as the request // options/context parameter, which would emit a duplicate parameter name. Rename the request @@ -1429,6 +1465,25 @@ private ScmMethodProvider BuildProtocolMethod(MethodProvider createRequestMethod MethodSignature? customSignature = null; PartialMethodCustomization.TryFindCustomSignature(client, methodName, parameters, out customSignature); + if (customSignature == null && client.CustomCodeView?.Methods is { Count: > 0 } + && ServiceMethod.Operation.IsMultipartFormData + && hasOptionalContent && convertedRequiredParameters.Count > 0) + { + // Older optional multipart signatures placed trailing required headers before the converted body parameters. + ParameterProvider[] legacyParameters = + [ + .. requiredParameters.Take(requiredBeforeContent), + .. requiredParameters.Skip(requiredBeforeContent + convertedRequiredParameters.Count), + .. convertedRequiredParameters, + .. optionalParameters, + requestOptionsParameter + ]; + if (PartialMethodCustomization.TryFindCustomSignature(client, methodName, legacyParameters, out customSignature)) + { + parameters = legacyParameters; + } + } + MethodSignature methodSignature; ParameterProvider[] bodyParameters; @@ -1560,8 +1615,8 @@ private static ParameterProvider ResolveRequestOptionsNameCollision( // operation/declaration order. Passing the protocol parameters positionally would therefore // bind them to the wrong CreateRequest parameters (for example, swapping an optional path // parameter with the request body). Reorder the arguments to match the CreateRequest - // signature by mapping each CreateRequest parameter to the protocol parameter with the same - // name. If the names cannot be reconciled, fall back to the original positional behavior. + // signature by matching each CreateRequest parameter to its protocol parameter, even when + // customization changes its name. If they cannot be reconciled, retain positional behavior. private ValueExpression[] BuildCreateRequestArguments( MethodSignature createRequestSignature, IReadOnlyList bodyParameters) @@ -1586,7 +1641,7 @@ private ValueExpression[] BuildCreateRequestArguments( bool allMatched = true; for (int i = 0; i < createRequestParameters.Count; i++) { - var match = bodyParameters.FirstOrDefault(p => p.Name == createRequestParameters[i].Name); + var match = FindUngroupedArgument(bodyParameters, createRequestParameters[i]); if (match is null) { allMatched = false; @@ -1607,10 +1662,8 @@ private ValueExpression[] BuildCreateRequestArguments( private static ValueExpression[]? BuildGroupedCreateRequestArguments( IReadOnlyList createRequestParameters, - IReadOnlyList protocolParameters, - Func? getArgument = null) + IReadOnlyList protocolParameters) { - getArgument ??= parameter => parameter; var arguments = new ValueExpression[createRequestParameters.Count]; for (int i = 0; i < createRequestParameters.Count; i++) @@ -1626,7 +1679,7 @@ private ValueExpression[] BuildCreateRequestArguments( return null; } - arguments[i] = getArgument(match); + arguments[i] = match; continue; } @@ -1641,7 +1694,7 @@ private ValueExpression[] BuildCreateRequestArguments( } var propertySegments = segments.Skip(1).Select(s => s.Name).ToList(); - var propertyExpression = groupModel.GetPropertyExpression(getArgument(groupParameter), propertySegments, out var leafProperty); + var propertyExpression = groupModel.GetPropertyExpression(groupParameter, propertySegments, out var leafProperty); // CreateRequest takes the serialized (string/number) form of an enum, so convert before forwarding. if (leafProperty.Type.IsEnum && !createRequestParameter.Type.IsEnum) @@ -1661,7 +1714,8 @@ private ValueExpression[] BuildCreateRequestArguments( /// /// Locates the protocol parameter to forward for a CreateRequest parameter that was not - /// folded into the options bag. The name alone is not reliable: a bag named after the request + /// folded into the options bag. Input identity survives custom parameter renames. The name + /// alone is not reliable: a bag named after the request /// options parameter causes that parameter to be renamed, so the original name now resolves to /// the bag. The type disambiguates in that case. /// @@ -1671,6 +1725,12 @@ private ValueExpression[] BuildCreateRequestArguments( { foreach (var parameter in protocolParameters) { + if (createRequestParameter.InputParameter != null + && ReferenceEquals(parameter.InputParameter, createRequestParameter.InputParameter)) + { + return parameter; + } + if (string.Equals(parameter.Name, createRequestParameter.Name, StringComparison.OrdinalIgnoreCase) && parameter.Type.Equals(createRequestParameter.Type)) { @@ -1697,99 +1757,17 @@ private ValueExpression[] BuildCreateRequestArguments( return typeMatch; } - private ParameterProvider ProcessOptionalParameters( - List optionalParameters, - List requiredParameters, - ref ParameterProvider requestOptionsParameter) - { - // If we need to make parameters required, make only the first optional parameter nullable required. - // This is to prevent ambiguous callsites with the RequestOptions parameter while avoiding overly aggressive required parameter conversion. - bool hasOptionalRequestContent = - optionalParameters.Any(p => p.IsContentParameter); - - // If there is an optional request content parameter, we need to make all parameters required up to and including the request content parameter - if (hasOptionalRequestContent) - { - int parametersMadeRequired = 0; - foreach (var optionalParameter in optionalParameters) - { - if (optionalParameter.IsContentParameter) - { - var nullableRequiredContent = - ScmKnownParameters.CreateRequestContent(optionalParameter.InputParameter, nullable: true); - requiredParameters.Add(nullableRequiredContent); - // Update the body param in the underlying collection - var bodyParamIndex = ProtocolMethodParameters.IndexOf(optionalParameter); - ProtocolMethodParameters[bodyParamIndex] = - nullableRequiredContent; - parametersMadeRequired++; - break; - } - - optionalParameter.DefaultValue = null; - optionalParameter.Type = optionalParameter.Type.WithNullable(true); - requiredParameters.Add(optionalParameter); - parametersMadeRequired++; - } - - optionalParameters.RemoveRange(0, parametersMadeRequired); - requestOptionsParameter = ScmKnownParameters.OptionalRequestOptions; - } - else - { - // If there is a required request content, then we don't need to make the optional parameters required - bool hasRequiredRequestContent = - requiredParameters.Any(p => p.IsContentParameter); - - if (hasRequiredRequestContent) - { - requestOptionsParameter = ScmKnownParameters.OptionalRequestOptions; - } - else - { - // Otherwise we need to make all parameters required - foreach (var optionalParameter in optionalParameters) - { - optionalParameter.DefaultValue = null; - optionalParameter.Type = optionalParameter.Type.WithNullable(true); - requiredParameters.Add(optionalParameter); - } - - optionalParameters.Clear(); - } - } - - return requestOptionsParameter; - } - private IEnumerable GetPagingMethodBody( TypeProvider collection, MethodSignature createRequestSignature, IReadOnlyList parameters, bool isConvenience, - IReadOnlyList? pagingProtocolParameters = null) + ParameterProvider? cancellationToken = null) { if (isConvenience) { - var conversionStatements = GetStackVariablesForProtocolParamConversion(ConvenienceMethodParameters, out var declarations); - var protocolArguments = GetProtocolMethodArguments(declarations); - - IReadOnlyList constructorArguments = protocolArguments; - if (RestClientProvider.ShouldGroupProtocolParameters(ServiceMethod)) - { - var protocolParameters = pagingProtocolParameters - ?? throw new InvalidOperationException("Paging protocol parameters are required to expand grouped arguments."); - var argumentMap = new Dictionary(); - for (int i = 0; i < protocolParameters.Count; i++) - { - argumentMap[protocolParameters[i]] = protocolArguments[i]; - } - - constructorArguments = BuildGroupedCreateRequestArguments( - createRequestSignature.Parameters, - protocolParameters, - parameter => argumentMap[parameter]) ?? protocolArguments; - } + var conversionStatements = GetStackVariablesForProtocolParamConversion(parameters, out var declarations); + var constructorArguments = GetMethodArguments(createRequestSignature, declarations, parameters, cancellationToken!); return [ @@ -2122,29 +2100,31 @@ private bool HasStreamingRequestOrResponse() private bool ShouldMakeProtocolMethodParametersRequired() { - var convenienceMethodParameterCount = ConvenienceMethodParameters.Count; if (!_generateConvenienceMethod) { return false; } + var convenienceParameters = RestClientProvider.GetMethodParameters(ServiceMethod, ScmMethodKind.Convenience, Client); + var convenienceMethodParameterCount = convenienceParameters.Count; if (convenienceMethodParameterCount == 0) { return true; } + var protocolParameters = RestClientProvider.GetMethodParameters(ServiceMethod, ScmMethodKind.Protocol, Client); for (int i = 0; i < convenienceMethodParameterCount; i++) { // If protocol parameter is required, and convenience is optional, we don't need any changes. - if (ProtocolMethodParameters[i].DefaultValue == null && ConvenienceMethodParameters[i].DefaultValue != null) + if (protocolParameters[i].DefaultValue == null && convenienceParameters[i].DefaultValue != null) { return false; } // If convenience is optional, and protocol is optional, we do need to make the protocol required. - if (ConvenienceMethodParameters[i].DefaultValue != null) + if (convenienceParameters[i].DefaultValue != null) { return true; } - if (!ProtocolMethodParameters[i].Type.Equals(ConvenienceMethodParameters[i].Type)) + if (!protocolParameters[i].Type.Equals(convenienceParameters[i].Type)) { return false; } diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs index 2ed618481e4..2ed8a130065 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs @@ -5558,6 +5558,204 @@ public void TestAcronymOperationMethodVariants(string kind) } } + [Test] + public async Task PublishedAcronymOrderPreservesForwarding( + [Values(false, true)] bool sameParameterTypes, + [Values(false, true)] bool omitOptionalParameter) + { + var targetType = sameParameterTypes ? InputPrimitiveType.String : InputPrimitiveType.Int32; + var operation = InputFactory.Operation( + "Send", + parameters: + [ + InputFactory.QueryParameter("sourceIpAddress", InputPrimitiveType.String, isRequired: true, serializedName: "source-ip"), + InputFactory.QueryParameter("targetDbName", targetType, isRequired: true, serializedName: "target-db"), + InputFactory.QueryParameter("filter", InputPrimitiveType.Boolean) + ], + responses: [InputFactory.OperationResponse([204])]); + var methodParameters = new List + { + InputFactory.MethodParameter("sourceIpAddress", InputPrimitiveType.String, isRequired: !omitOptionalParameter, location: InputRequestLocation.Query, serializedName: "source-ip"), + InputFactory.MethodParameter("targetDbName", targetType, isRequired: true, location: InputRequestLocation.Query, serializedName: "target-db") + }; + if (!omitOptionalParameter) + { + methodParameters.Add(InputFactory.MethodParameter("filter", InputPrimitiveType.Boolean, location: InputRequestLocation.Query)); + } + var serviceMethod = InputFactory.BasicServiceMethod("Send", operation, parameters: methodParameters); + var inputClient = InputFactory.Client("TestClient", methods: [serviceMethod]); + var generator = await MockHelpers.LoadMockGeneratorAsync( + clients: () => [inputClient], + lastContractCompilation: async () => await Helpers.GetCompilationFromDirectoryAsync(sameParameterTypes ? "Same" : "Mixed"), + configuration: """{"disable-xml-docs": false, "package-name": "Sample"}"""); + var client = generator.Object.OutputLibrary.TypeProviders.OfType().Single(); + client.ProcessTypeForBackCompatibility(); + + var protocols = client.Methods.OfType().Where(method => method.Kind == ScmMethodKind.Protocol).ToArray(); + Assert.AreEqual(2, protocols.Length); + foreach (var protocol in protocols) + { + bool isAsync = protocol.Signature.Name.EndsWith("Async", StringComparison.Ordinal); + string[] expectedProtocolNames = isAsync + ? ["sourceIpAddress", "targetDbName", "filter", "options"] + : ["targetDbName", "sourceIpAddress", "filter", "options"]; + CollectionAssert.AreEqual(expectedProtocolNames, protocol.Signature.Parameters.Select(parameter => parameter.Name)); + using var writer = new CodeWriter(); + writer.WriteMethod(protocol); + var methodText = writer.ToString(false); + foreach (var name in expectedProtocolNames) + { + StringAssert.Contains($"", methodText); + } + var requestSyntax = CSharpSyntaxTree.ParseText(protocol.BodyStatements!.ToDisplayString()).GetRoot(); + var requestCall = requestSyntax.DescendantNodes().OfType().Single(invocation => + invocation.Expression is MemberAccessExpressionSyntax member && member.Name.Identifier.ValueText == "CreateSendRequest"); + CollectionAssert.AreEqual( + new[] { "sourceIpAddress", "targetDbName", "filter", "options" }, + requestCall.ArgumentList.Arguments.Select(argument => argument.Expression.ToString())); + + var convenience = client.Methods.OfType().Single(method => + method.Kind == ScmMethodKind.Convenience && method.Signature.Name == protocol.Signature.Name); + CollectionAssert.AreEqual( + omitOptionalParameter ? new[] { "targetDbName", "sourceIpAddress", "cancellationToken" } : new[] { "targetDbName", "sourceIpAddress", "filter", "cancellationToken" }, + convenience.Signature.Parameters.Select(parameter => parameter.Name)); + var syntax = CSharpSyntaxTree.ParseText(convenience.BodyStatements!.ToDisplayString()).GetRoot(); + var call = syntax.DescendantNodes().OfType().Single(invocation => + invocation.Expression is MemberAccessExpressionSyntax member && member.Name.Identifier.ValueText == protocol.Signature.Name); + CollectionAssert.AreEqual( + expectedProtocolNames.Take(2).Concat(omitOptionalParameter ? [] : new[] { "filter" }).Append("cancellationToken.ToRequestOptions()"), + call.ArgumentList.Arguments.Select(argument => argument.Expression.ToString())); + } + + var references = AppDomain.CurrentDomain.GetAssemblies() + .Where(assembly => !assembly.IsDynamic && !string.IsNullOrEmpty(assembly.Location)) + .Select(assembly => MetadataReference.CreateFromFile(assembly.Location)) + .Append(MetadataReference.CreateFromFile(typeof(Microsoft.Extensions.Configuration.IConfigurationSection).Assembly.Location)); + var providers = generator.Object.OutputLibrary.TypeProviders + .Where(provider => provider is not Utf8JsonBinaryContentDefinition and not BinaryContentHelperDefinition); + var trees = providers.Select(provider => new TypeProviderWriter(provider).Write()) + .Select(file => CSharpSyntaxTree.ParseText(file.Content, path: file.Name)); + var compilation = CSharpCompilation.Create( + "PublishedAcronymOrder", trees, references, + new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, generalDiagnosticOption: ReportDiagnostic.Error)); + Assert.IsEmpty(compilation.GetDiagnostics().Where(diagnostic => diagnostic.Severity == DiagnosticSeverity.Error) + .Select(diagnostic => diagnostic.ToString())); + } + + [TestCase(false)] + [TestCase(true)] + public async Task AcronymParameterRestorationRequiresMatchingSignature(bool matchingParameterType) + { + var valueType = matchingParameterType ? InputPrimitiveType.Int32 : InputPrimitiveType.Boolean; + var operation = InputFactory.Operation( + "Send", + parameters: + [ + InputFactory.QueryParameter("sourceIpAddress", InputPrimitiveType.String, isRequired: true), + InputFactory.QueryParameter("newValue", valueType, isRequired: true) + ], + responses: [InputFactory.OperationResponse([204])]); + var serviceMethod = InputFactory.BasicServiceMethod( + "Send", operation, + parameters: + [ + InputFactory.MethodParameter("sourceIpAddress", InputPrimitiveType.String, isRequired: true, location: InputRequestLocation.Query), + InputFactory.MethodParameter("newValue", valueType, isRequired: true, location: InputRequestLocation.Query) + ]); + var inputClient = InputFactory.Client("TestClient", methods: [serviceMethod]); + await MockHelpers.LoadMockGeneratorAsync( + clients: () => [inputClient], + lastContractCompilation: async () => await Helpers.GetCompilationFromDirectoryAsync()); + var client = ScmCodeModelGenerator.Instance.TypeFactory.CreateClient(inputClient)!; + client.ProcessTypeForBackCompatibility(); + var methods = client.Methods.OfType().Where(method => method.Signature.Name is "Send" or "SendAsync").ToArray(); + Assert.AreEqual(4, methods.Length); + + foreach (var method in methods) + { + CollectionAssert.AreEqual( + matchingParameterType ? new[] { "sourceIpAddress", "oldValue" } : new[] { "sourceIPAddress", "newValue" }, + method.Signature.Parameters.Take(2).Select(parameter => parameter.Name)); + } + } + + [TestCase("LastContract")] + [TestCase("DistinctLastContract")] + [TestCase("CaseOnlyLastContract")] + [TestCase("PrivateLastContract")] + [TestCase("TypeMismatchLastContract")] + [TestCase("Custom")] + [TestCase("CustomWithLastContract")] + public async Task AcronymOperationParameterNamesPreserveSignatures(string signatureSource) + { + var custom = signatureSource.StartsWith("Custom"); + var distinctNames = signatureSource == "DistinctLastContract"; + var hasMatchingContract = signatureSource is not ("PrivateLastContract" or "TypeMismatchLastContract"); + var lastContractSource = custom ? "LastContract" : signatureSource; + string[] inputNames = ["sourceIpAddress", "targetDbName", "guestOsType", "IPv4Address", "IPv6Address"]; + string[] contractNames = custom + ? ["customIpAddress", "customDbName", "customOsType", "customIPv4Address", "customIPv6Address"] + : ["sourceIpAddress", "targetDbName", "guestOsType", "iPv4Address", "iPv6Address"]; + var operation = InputFactory.Operation( + "Send", + parameters: inputNames.Select(name => InputFactory.QueryParameter(name, InputPrimitiveType.String, isRequired: true)).ToArray(), + responses: [InputFactory.OperationResponse([204])]); + var serviceMethod = InputFactory.BasicServiceMethod( + "Send", + operation, + parameters: inputNames.Select(name => InputFactory.MethodParameter(name, InputPrimitiveType.String, isRequired: true, location: InputRequestLocation.Query)).ToArray()); + var inputClient = InputFactory.Client("TestClient", methods: [serviceMethod]); + var generator = await MockHelpers.LoadMockGeneratorAsync( + clients: () => [inputClient], + compilation: custom ? async () => await Helpers.GetCompilationFromDirectoryAsync("Custom") : null, + lastContractCompilation: signatureSource == "Custom" ? null : async () => await Helpers.GetCompilationFromDirectoryAsync(lastContractSource), + configuration: """{"disable-xml-docs": false, "package-name": "Sample"}"""); + var client = generator.Object.OutputLibrary.TypeProviders.OfType().Single(); + client.ProcessTypeForBackCompatibility(); + var methods = client.Methods.OfType().Where(method => method.Signature.Name is "Send" or "SendAsync").ToArray(); + Assert.AreEqual(4, methods.Length); + foreach (var method in methods) + { + var suffix = (method.Signature.Name.EndsWith("Async") ? "Async" : "Sync") + + (method.Kind == ScmMethodKind.Protocol ? "Protocol" : "Convenience"); + var expectedNames = distinctNames ? contractNames.Select(name => name + suffix).ToArray() : contractNames; + if (!hasMatchingContract) + { + expectedNames = ["sourceIPAddress", "targetDBName", "guestOSType", "ipv4Address", "ipv6Address"]; + } + if (signatureSource == "CaseOnlyLastContract") + { + expectedNames = suffix switch + { + "SyncProtocol" => ["sourceIpAddress", "targetDbName", "guestOsType", "iPv4Address", "iPv6Address"], + "AsyncProtocol" => ["sourceIPAddress", "targetDBName", "guestOSType", "ipv4Address", "ipv6Address"], + "SyncConvenience" => ["SourceIpAddress", "TargetDbName", "GuestOsType", "IPv4Address", "IPv6Address"], + _ => ["SOURCEIPADDRESS", "TARGETDbNAME", "GUESTOsTYPE", "IPV4ADDRESS", "IPV6ADDRESS"] + }; + } + CollectionAssert.AreEqual(expectedNames, method.Signature.Parameters.Take(inputNames.Length).Select(parameter => parameter.Name)); + Assert.AreEqual(custom, method.IsPartialMethod); + using var writer = new CodeWriter(); + writer.WriteMethod(method); + var text = writer.ToString(false); + foreach (var name in expectedNames) + { + StringAssert.Contains($"", text); + StringAssert.Contains($"", text); + StringAssert.Contains($"nameof({name})", text); + } + var target = method.Kind == ScmMethodKind.Protocol ? "CreateSendRequest" : method.Signature.Name; + var trailingArgument = method.Kind == ScmMethodKind.Protocol ? "options" : "cancellationToken.ToRequestOptions()"; + StringAssert.Contains($"this.{target}({string.Join(", ", expectedNames)}, {trailingArgument})", text); + if (method.Kind == ScmMethodKind.Convenience && method.Signature.Name.EndsWith("Async")) + { + Assert.AreEqual( + Helpers.GetExpectedFromFile(custom ? "Custom" : hasMatchingContract ? signatureSource : "Normalized"), + method.BodyStatements!.ToDisplayString()); + } + } + } + [TestCase("GetIpAddress", "GetIpAddress")] [TestCase("GetDbStatus", "GetDbStatus")] [TestCase("GetOsProfile", "GetOsProfile")] @@ -5649,6 +5847,51 @@ await MockHelpers.LoadMockGeneratorAsync( Assert.AreEqual(2, methods.Count(m => m.IsPartialMethod)); } + [TestCase("LastContract", false)] + [TestCase("LastContract", true)] + [TestCase("Custom", false)] + [TestCase("Custom", true)] + [TestCase("CustomWithLastContract", false)] + [TestCase("CustomWithLastContract", true)] + public async Task AcronymNamedArgumentsUseProtocolSignature(string signatureSource, bool async) + { + var operation = InputFactory.Operation( + "Send", + parameters: + [ + InputFactory.QueryParameter("id", InputPrimitiveType.String, isRequired: true), + InputFactory.QueryParameter("filter", InputPrimitiveType.String), + InputFactory.QueryParameter("sourceIpAddress", InputPrimitiveType.String) + ], + responses: [InputFactory.OperationResponse([204])]); + var serviceMethod = InputFactory.BasicServiceMethod( + "Send", + operation, + parameters: + [ + InputFactory.MethodParameter("id", InputPrimitiveType.String, isRequired: true, location: InputRequestLocation.Query), + InputFactory.MethodParameter("sourceIpAddress", InputPrimitiveType.String, location: InputRequestLocation.Query) + ]); + var inputClient = InputFactory.Client("TestClient", methods: [serviceMethod]); + var custom = signatureSource.StartsWith("Custom"); + var generator = await MockHelpers.LoadMockGeneratorAsync( + clients: () => [inputClient], + compilation: custom ? async () => await Helpers.GetCompilationFromDirectoryAsync("Custom") : null, + lastContractCompilation: signatureSource == "Custom" ? null : async () => await Helpers.GetCompilationFromDirectoryAsync("LastContract")); + var client = generator.Object.OutputLibrary.TypeProviders.OfType().Single(); + client.ProcessTypeForBackCompatibility(); + var methodName = async ? "SendAsync" : "Send"; + var convenienceMethod = client.Methods.OfType().Single( + method => method.Kind == ScmMethodKind.Convenience && method.Signature.Name == methodName); + var protocolMethod = client.Methods.OfType().Single( + method => method.Kind == ScmMethodKind.Protocol && method.Signature.Name == methodName); + Assert.AreEqual(custom ? "customIpWire" : "sourceIpAddressWire", protocolMethod.Signature.Parameters[2].Name); + Assert.AreEqual(custom ? "customOptions" : "legacyOptions", protocolMethod.Signature.Parameters[3].Name); + Assert.AreEqual( + Helpers.GetExpectedFromFile($"{(custom ? "Custom" : "LastContract")},{(async ? "Async" : "Sync")}"), + convenienceMethod.BodyStatements!.ToDisplayString()); + } + [Test] public async Task TestOperationNamePreservesUrlSuffixFromLastContract() { diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/AcronymNamedArgumentsUseProtocolSignature(Custom)/TestClient.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/AcronymNamedArgumentsUseProtocolSignature(Custom)/TestClient.cs new file mode 100644 index 00000000000..3bc3558bfd4 --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/AcronymNamedArgumentsUseProtocolSignature(Custom)/TestClient.cs @@ -0,0 +1,15 @@ +using System.ClientModel; +using System.ClientModel.Primitives; +using System.Threading; +using System.Threading.Tasks; + +namespace Sample +{ + public partial class TestClient + { + public partial ClientResult Send(string customId, string customFilter, string customIpWire, RequestOptions customOptions); + public partial Task SendAsync(string customId, string customFilter, string customIpWire, RequestOptions customOptions); + public partial ClientResult Send(string customId, string customIpValue, CancellationToken customToken); + public partial Task SendAsync(string customId, string customIpValue, CancellationToken customToken); + } +} diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/AcronymNamedArgumentsUseProtocolSignature(Custom,Async).cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/AcronymNamedArgumentsUseProtocolSignature(Custom,Async).cs new file mode 100644 index 00000000000..f7a36c72caa --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/AcronymNamedArgumentsUseProtocolSignature(Custom,Async).cs @@ -0,0 +1,3 @@ +global::Sample.Argument.AssertNotNullOrEmpty(customId, nameof(customId)); + +return await this.SendAsync(customId, customFilter: null, customIpWire: customIpValue, customOptions: customToken.ToRequestOptions()).ConfigureAwait(false); diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/AcronymNamedArgumentsUseProtocolSignature(Custom,Sync).cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/AcronymNamedArgumentsUseProtocolSignature(Custom,Sync).cs new file mode 100644 index 00000000000..2dd91a1d44d --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/AcronymNamedArgumentsUseProtocolSignature(Custom,Sync).cs @@ -0,0 +1,3 @@ +global::Sample.Argument.AssertNotNullOrEmpty(customId, nameof(customId)); + +return this.Send(customId, customFilter: null, customIpWire: customIpValue, customOptions: customToken.ToRequestOptions()); diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/AcronymNamedArgumentsUseProtocolSignature(LastContract)/TestClient.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/AcronymNamedArgumentsUseProtocolSignature(LastContract)/TestClient.cs new file mode 100644 index 00000000000..cea65fe0065 --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/AcronymNamedArgumentsUseProtocolSignature(LastContract)/TestClient.cs @@ -0,0 +1,15 @@ +using System.ClientModel; +using System.ClientModel.Primitives; +using System.Threading; +using System.Threading.Tasks; + +namespace Sample +{ + public partial class TestClient + { + public virtual ClientResult Send(string id, string filter, string sourceIpAddressWire, RequestOptions legacyOptions) => default; + public virtual Task SendAsync(string id, string filter, string sourceIpAddressWire, RequestOptions legacyOptions) => default; + public virtual ClientResult Send(string id, string sourceIpAddressValue = default, CancellationToken cancellationToken = default) => default; + public virtual Task SendAsync(string id, string sourceIpAddressValue = default, CancellationToken cancellationToken = default) => default; + } +} diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/AcronymNamedArgumentsUseProtocolSignature(LastContract,Async).cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/AcronymNamedArgumentsUseProtocolSignature(LastContract,Async).cs new file mode 100644 index 00000000000..e0d864def7d --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/AcronymNamedArgumentsUseProtocolSignature(LastContract,Async).cs @@ -0,0 +1,3 @@ +global::Sample.Argument.AssertNotNullOrEmpty(id, nameof(id)); + +return await this.SendAsync(id, filter: null, sourceIpAddressWire: sourceIpAddressValue, legacyOptions: cancellationToken.ToRequestOptions()).ConfigureAwait(false); diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/AcronymNamedArgumentsUseProtocolSignature(LastContract,Sync).cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/AcronymNamedArgumentsUseProtocolSignature(LastContract,Sync).cs new file mode 100644 index 00000000000..b13a9b310bb --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/AcronymNamedArgumentsUseProtocolSignature(LastContract,Sync).cs @@ -0,0 +1,3 @@ +global::Sample.Argument.AssertNotNullOrEmpty(id, nameof(id)); + +return this.Send(id, filter: null, sourceIpAddressWire: sourceIpAddressValue, legacyOptions: cancellationToken.ToRequestOptions()); diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/AcronymOperationParameterNamesPreserveSignatures(CaseOnlyLastContract).cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/AcronymOperationParameterNamesPreserveSignatures(CaseOnlyLastContract).cs new file mode 100644 index 00000000000..907742268f5 --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/AcronymOperationParameterNamesPreserveSignatures(CaseOnlyLastContract).cs @@ -0,0 +1,7 @@ +global::Sample.Argument.AssertNotNullOrEmpty(SOURCEIPADDRESS, nameof(SOURCEIPADDRESS)); +global::Sample.Argument.AssertNotNullOrEmpty(TARGETDbNAME, nameof(TARGETDbNAME)); +global::Sample.Argument.AssertNotNullOrEmpty(GUESTOsTYPE, nameof(GUESTOsTYPE)); +global::Sample.Argument.AssertNotNullOrEmpty(IPV4ADDRESS, nameof(IPV4ADDRESS)); +global::Sample.Argument.AssertNotNullOrEmpty(IPV6ADDRESS, nameof(IPV6ADDRESS)); + +return await this.SendAsync(SOURCEIPADDRESS, TARGETDbNAME, GUESTOsTYPE, IPV4ADDRESS, IPV6ADDRESS, cancellationToken.ToRequestOptions()).ConfigureAwait(false); diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/AcronymOperationParameterNamesPreserveSignatures(CaseOnlyLastContract)/TestClient.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/AcronymOperationParameterNamesPreserveSignatures(CaseOnlyLastContract)/TestClient.cs new file mode 100644 index 00000000000..67bf30b0450 --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/AcronymOperationParameterNamesPreserveSignatures(CaseOnlyLastContract)/TestClient.cs @@ -0,0 +1,15 @@ +using System.ClientModel; +using System.ClientModel.Primitives; +using System.Threading; +using System.Threading.Tasks; + +namespace Sample +{ + public partial class TestClient + { + public virtual ClientResult Send(string sourceIpAddress, string targetDbName, string guestOsType, string iPv4Address, string iPv6Address, RequestOptions options) => default; + public virtual Task SendAsync(string sourceIPAddress, string targetDBName, string guestOSType, string ipv4Address, string ipv6Address, RequestOptions options) => default; + public virtual ClientResult Send(string SourceIpAddress, string TargetDbName, string GuestOsType, string IPv4Address, string IPv6Address, CancellationToken cancellationToken = default) => default; + public virtual Task SendAsync(string SOURCEIPADDRESS, string TARGETDbNAME, string GUESTOsTYPE, string IPV4ADDRESS, string IPV6ADDRESS, CancellationToken cancellationToken = default) => default; + } +} diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/AcronymOperationParameterNamesPreserveSignatures(Custom).cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/AcronymOperationParameterNamesPreserveSignatures(Custom).cs new file mode 100644 index 00000000000..70dc0c8a64c --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/AcronymOperationParameterNamesPreserveSignatures(Custom).cs @@ -0,0 +1,7 @@ +global::Sample.Argument.AssertNotNullOrEmpty(customIpAddress, nameof(customIpAddress)); +global::Sample.Argument.AssertNotNullOrEmpty(customDbName, nameof(customDbName)); +global::Sample.Argument.AssertNotNullOrEmpty(customOsType, nameof(customOsType)); +global::Sample.Argument.AssertNotNullOrEmpty(customIPv4Address, nameof(customIPv4Address)); +global::Sample.Argument.AssertNotNullOrEmpty(customIPv6Address, nameof(customIPv6Address)); + +return await this.SendAsync(customIpAddress, customDbName, customOsType, customIPv4Address, customIPv6Address, cancellationToken.ToRequestOptions()).ConfigureAwait(false); diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/AcronymOperationParameterNamesPreserveSignatures(Custom)/TestClient.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/AcronymOperationParameterNamesPreserveSignatures(Custom)/TestClient.cs new file mode 100644 index 00000000000..e7c8677d511 --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/AcronymOperationParameterNamesPreserveSignatures(Custom)/TestClient.cs @@ -0,0 +1,15 @@ +using System.ClientModel; +using System.ClientModel.Primitives; +using System.Threading; +using System.Threading.Tasks; + +namespace Sample +{ + public partial class TestClient + { + public partial ClientResult Send(string customIpAddress, string customDbName, string customOsType, string customIPv4Address, string customIPv6Address, RequestOptions options); + public partial Task SendAsync(string customIpAddress, string customDbName, string customOsType, string customIPv4Address, string customIPv6Address, RequestOptions options); + public partial ClientResult Send(string customIpAddress, string customDbName, string customOsType, string customIPv4Address, string customIPv6Address, CancellationToken cancellationToken); + public partial Task SendAsync(string customIpAddress, string customDbName, string customOsType, string customIPv4Address, string customIPv6Address, CancellationToken cancellationToken); + } +} diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/AcronymOperationParameterNamesPreserveSignatures(DistinctLastContract).cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/AcronymOperationParameterNamesPreserveSignatures(DistinctLastContract).cs new file mode 100644 index 00000000000..842fe345fa1 --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/AcronymOperationParameterNamesPreserveSignatures(DistinctLastContract).cs @@ -0,0 +1,7 @@ +global::Sample.Argument.AssertNotNullOrEmpty(sourceIpAddressAsyncConvenience, nameof(sourceIpAddressAsyncConvenience)); +global::Sample.Argument.AssertNotNullOrEmpty(targetDbNameAsyncConvenience, nameof(targetDbNameAsyncConvenience)); +global::Sample.Argument.AssertNotNullOrEmpty(guestOsTypeAsyncConvenience, nameof(guestOsTypeAsyncConvenience)); +global::Sample.Argument.AssertNotNullOrEmpty(iPv4AddressAsyncConvenience, nameof(iPv4AddressAsyncConvenience)); +global::Sample.Argument.AssertNotNullOrEmpty(iPv6AddressAsyncConvenience, nameof(iPv6AddressAsyncConvenience)); + +return await this.SendAsync(sourceIpAddressAsyncConvenience, targetDbNameAsyncConvenience, guestOsTypeAsyncConvenience, iPv4AddressAsyncConvenience, iPv6AddressAsyncConvenience, cancellationToken.ToRequestOptions()).ConfigureAwait(false); diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/AcronymOperationParameterNamesPreserveSignatures(DistinctLastContract)/TestClient.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/AcronymOperationParameterNamesPreserveSignatures(DistinctLastContract)/TestClient.cs new file mode 100644 index 00000000000..9ac99660185 --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/AcronymOperationParameterNamesPreserveSignatures(DistinctLastContract)/TestClient.cs @@ -0,0 +1,15 @@ +using System.ClientModel; +using System.ClientModel.Primitives; +using System.Threading; +using System.Threading.Tasks; + +namespace Sample +{ + public partial class TestClient + { + public virtual ClientResult Send(string sourceIpAddressSyncProtocol, string targetDbNameSyncProtocol, string guestOsTypeSyncProtocol, string iPv4AddressSyncProtocol, string iPv6AddressSyncProtocol, RequestOptions options) => default; + public virtual Task SendAsync(string sourceIpAddressAsyncProtocol, string targetDbNameAsyncProtocol, string guestOsTypeAsyncProtocol, string iPv4AddressAsyncProtocol, string iPv6AddressAsyncProtocol, RequestOptions options) => default; + public virtual ClientResult Send(string sourceIpAddressSyncConvenience, string targetDbNameSyncConvenience, string guestOsTypeSyncConvenience, string iPv4AddressSyncConvenience, string iPv6AddressSyncConvenience, CancellationToken cancellationToken = default) => default; + public virtual Task SendAsync(string sourceIpAddressAsyncConvenience, string targetDbNameAsyncConvenience, string guestOsTypeAsyncConvenience, string iPv4AddressAsyncConvenience, string iPv6AddressAsyncConvenience, CancellationToken cancellationToken = default) => default; + } +} diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/AcronymOperationParameterNamesPreserveSignatures(LastContract).cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/AcronymOperationParameterNamesPreserveSignatures(LastContract).cs new file mode 100644 index 00000000000..6134b65513a --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/AcronymOperationParameterNamesPreserveSignatures(LastContract).cs @@ -0,0 +1,7 @@ +global::Sample.Argument.AssertNotNullOrEmpty(sourceIpAddress, nameof(sourceIpAddress)); +global::Sample.Argument.AssertNotNullOrEmpty(targetDbName, nameof(targetDbName)); +global::Sample.Argument.AssertNotNullOrEmpty(guestOsType, nameof(guestOsType)); +global::Sample.Argument.AssertNotNullOrEmpty(iPv4Address, nameof(iPv4Address)); +global::Sample.Argument.AssertNotNullOrEmpty(iPv6Address, nameof(iPv6Address)); + +return await this.SendAsync(sourceIpAddress, targetDbName, guestOsType, iPv4Address, iPv6Address, cancellationToken.ToRequestOptions()).ConfigureAwait(false); diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/AcronymOperationParameterNamesPreserveSignatures(LastContract)/TestClient.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/AcronymOperationParameterNamesPreserveSignatures(LastContract)/TestClient.cs new file mode 100644 index 00000000000..113d83b734d --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/AcronymOperationParameterNamesPreserveSignatures(LastContract)/TestClient.cs @@ -0,0 +1,15 @@ +using System.ClientModel; +using System.ClientModel.Primitives; +using System.Threading; +using System.Threading.Tasks; + +namespace Sample +{ + public partial class TestClient + { + public virtual ClientResult Send(string sourceIpAddress, string targetDbName, string guestOsType, string iPv4Address, string iPv6Address, RequestOptions options) => default; + public virtual Task SendAsync(string sourceIpAddress, string targetDbName, string guestOsType, string iPv4Address, string iPv6Address, RequestOptions options) => default; + public virtual ClientResult Send(string sourceIpAddress, string targetDbName, string guestOsType, string iPv4Address, string iPv6Address, CancellationToken cancellationToken = default) => default; + public virtual Task SendAsync(string sourceIpAddress, string targetDbName, string guestOsType, string iPv4Address, string iPv6Address, CancellationToken cancellationToken = default) => default; + } +} diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/AcronymOperationParameterNamesPreserveSignatures(Normalized).cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/AcronymOperationParameterNamesPreserveSignatures(Normalized).cs new file mode 100644 index 00000000000..47535f75e93 --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/AcronymOperationParameterNamesPreserveSignatures(Normalized).cs @@ -0,0 +1,7 @@ +global::Sample.Argument.AssertNotNullOrEmpty(sourceIPAddress, nameof(sourceIPAddress)); +global::Sample.Argument.AssertNotNullOrEmpty(targetDBName, nameof(targetDBName)); +global::Sample.Argument.AssertNotNullOrEmpty(guestOSType, nameof(guestOSType)); +global::Sample.Argument.AssertNotNullOrEmpty(ipv4Address, nameof(ipv4Address)); +global::Sample.Argument.AssertNotNullOrEmpty(ipv6Address, nameof(ipv6Address)); + +return await this.SendAsync(sourceIPAddress, targetDBName, guestOSType, ipv4Address, ipv6Address, cancellationToken.ToRequestOptions()).ConfigureAwait(false); diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/AcronymOperationParameterNamesPreserveSignatures(PrivateLastContract)/TestClient.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/AcronymOperationParameterNamesPreserveSignatures(PrivateLastContract)/TestClient.cs new file mode 100644 index 00000000000..f8a3f2df89e --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/AcronymOperationParameterNamesPreserveSignatures(PrivateLastContract)/TestClient.cs @@ -0,0 +1,15 @@ +using System.ClientModel; +using System.ClientModel.Primitives; +using System.Threading; +using System.Threading.Tasks; + +namespace Sample +{ + public partial class TestClient + { + private ClientResult Send(string sourceIpAddress, string targetDbName, string guestOsType, string iPv4Address, string iPv6Address, RequestOptions options) => default; + private Task SendAsync(string sourceIpAddress, string targetDbName, string guestOsType, string iPv4Address, string iPv6Address, RequestOptions options) => default; + private ClientResult Send(string sourceIpAddress, string targetDbName, string guestOsType, string iPv4Address, string iPv6Address, CancellationToken cancellationToken = default) => default; + private Task SendAsync(string sourceIpAddress, string targetDbName, string guestOsType, string iPv4Address, string iPv6Address, CancellationToken cancellationToken = default) => default; + } +} diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/AcronymOperationParameterNamesPreserveSignatures(TypeMismatchLastContract)/TestClient.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/AcronymOperationParameterNamesPreserveSignatures(TypeMismatchLastContract)/TestClient.cs new file mode 100644 index 00000000000..08257265734 --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/AcronymOperationParameterNamesPreserveSignatures(TypeMismatchLastContract)/TestClient.cs @@ -0,0 +1,15 @@ +using System.ClientModel; +using System.ClientModel.Primitives; +using System.Threading; +using System.Threading.Tasks; + +namespace Sample +{ + public partial class TestClient + { + public virtual ClientResult Send(int sourceIpAddress, int targetDbName, int guestOsType, int iPv4Address, int iPv6Address, RequestOptions options) => default; + public virtual Task SendAsync(int sourceIpAddress, int targetDbName, int guestOsType, int iPv4Address, int iPv6Address, RequestOptions options) => default; + public virtual ClientResult Send(int sourceIpAddress, int targetDbName, int guestOsType, int iPv4Address, int iPv6Address, CancellationToken cancellationToken = default) => default; + public virtual Task SendAsync(int sourceIpAddress, int targetDbName, int guestOsType, int iPv4Address, int iPv6Address, CancellationToken cancellationToken = default) => default; + } +} diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/AcronymParameterRestorationRequiresMatchingSignature/TestClient.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/AcronymParameterRestorationRequiresMatchingSignature/TestClient.cs new file mode 100644 index 00000000000..03fc441d7ac --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/AcronymParameterRestorationRequiresMatchingSignature/TestClient.cs @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.ClientModel; +using System.ClientModel.Primitives; +using System.Threading; +using System.Threading.Tasks; + +namespace Sample +{ + public partial class TestClient + { + public virtual ClientResult Send(string sourceIpAddress, int oldValue, RequestOptions options) => default; + public virtual Task SendAsync(string sourceIpAddress, int oldValue, RequestOptions options) => default; + public virtual ClientResult Send(string sourceIpAddress, int oldValue, CancellationToken cancellationToken = default) => default; + public virtual Task SendAsync(string sourceIpAddress, int oldValue, CancellationToken cancellationToken = default) => default; + } +} diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/PublishedAcronymOrderPreservesForwarding(Mixed)/TestClient.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/PublishedAcronymOrderPreservesForwarding(Mixed)/TestClient.cs new file mode 100644 index 00000000000..f58f3af37cb --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/PublishedAcronymOrderPreservesForwarding(Mixed)/TestClient.cs @@ -0,0 +1,20 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.ClientModel; +using System.ClientModel.Primitives; +using System.Threading; +using System.Threading.Tasks; + +namespace Sample +{ + public partial class TestClient + { + public virtual ClientResult Send(int targetDbName, string sourceIpAddress, bool? filter = default, RequestOptions options = default) => default; + public virtual Task SendAsync(string sourceIpAddress, int targetDbName, bool? filter = default, RequestOptions options = default) => default; + public virtual ClientResult Send(int targetDbName, string sourceIpAddress = default, CancellationToken cancellationToken = default) => default; + public virtual Task SendAsync(int targetDbName, string sourceIpAddress = default, CancellationToken cancellationToken = default) => default; + public virtual ClientResult Send(int targetDbName, string sourceIpAddress, bool? filter, CancellationToken cancellationToken = default) => default; + public virtual Task SendAsync(int targetDbName, string sourceIpAddress, bool? filter, CancellationToken cancellationToken = default) => default; + } +} diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/PublishedAcronymOrderPreservesForwarding(Same)/TestClient.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/PublishedAcronymOrderPreservesForwarding(Same)/TestClient.cs new file mode 100644 index 00000000000..c16aaa1c71a --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/PublishedAcronymOrderPreservesForwarding(Same)/TestClient.cs @@ -0,0 +1,20 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.ClientModel; +using System.ClientModel.Primitives; +using System.Threading; +using System.Threading.Tasks; + +namespace Sample +{ + public partial class TestClient + { + public virtual ClientResult Send(string targetDbName, string sourceIpAddress, bool? filter = default, RequestOptions options = default) => default; + public virtual Task SendAsync(string sourceIpAddress, string targetDbName, bool? filter = default, RequestOptions options = default) => default; + public virtual ClientResult Send(string targetDbName, string sourceIpAddress = default, CancellationToken cancellationToken = default) => default; + public virtual Task SendAsync(string targetDbName, string sourceIpAddress = default, CancellationToken cancellationToken = default) => default; + public virtual ClientResult Send(string targetDbName, string sourceIpAddress, bool? filter, CancellationToken cancellationToken = default) => default; + public virtual Task SendAsync(string targetDbName, string sourceIpAddress, bool? filter, CancellationToken cancellationToken = default) => default; + } +} diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/TestMultipartClient_UploadMethods_OptionalBody.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/TestMultipartClient_UploadMethods_OptionalBody.cs index 7fdbf8b8979..33345c5818c 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/TestMultipartClient_UploadMethods_OptionalBody.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientProviders/TestData/ClientProviderTests/TestMultipartClient_UploadMethods_OptionalBody.cs @@ -19,7 +19,7 @@ public partial class MultipartClient return global::System.ClientModel.ClientResult.FromResponse(Pipeline.ProcessMessage(message, options)); } - public virtual async global::System.Threading.Tasks.Task UploadAsync(string contentType, global::System.ClientModel.BinaryContent content, global::System.ClientModel.Primitives.RequestOptions options = null) + public virtual async global::System.Threading.Tasks.Task UploadAsync(global::System.ClientModel.BinaryContent content, string contentType, global::System.ClientModel.Primitives.RequestOptions options = null) { using global::System.ClientModel.Primitives.PipelineMessage message = this.CreateUploadRequest(content, contentType, options); return global::System.ClientModel.ClientResult.FromResponse(await Pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientSettingsProviderTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientSettingsProviderTests.cs index 3978b18b967..da91049f964 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientSettingsProviderTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ClientSettingsProviderTests.cs @@ -24,6 +24,31 @@ namespace Microsoft.TypeSpec.Generator.ClientModel.Tests.Providers { public class ClientSettingsProviderTests { + [TestCase("sourceIpAddress", "SourceIpAddress")] + [TestCase("targetDbName", "TargetDbName")] + [TestCase("guestOsType", "GuestOsType")] + public void ClientScopedAcronymsPreserveConstructorAndSettingsNames(string name, string propertyName) + { + var parameter = InputFactory.MethodParameter( + name, InputPrimitiveType.String, isRequired: true, scope: InputParameterScope.Client); + var inputClient = InputFactory.Client("TestClient", parameters: [parameter]); + MockHelpers.LoadMockGenerator(clients: () => [inputClient]); + var client = ScmCodeModelGenerator.Instance.TypeFactory.CreateClient(inputClient)!; + var constructors = client.Constructors.Where(constructor => + constructor.Signature.Modifiers.HasFlag(MethodSignatureModifiers.Public) + && constructor.Signature.Parameters.Any(candidate => ReferenceEquals(candidate.InputParameter, parameter))).ToArray(); + + Assert.IsNotEmpty(constructors); + foreach (var constructor in constructors) + { + Assert.AreEqual(name, constructor.Signature.Parameters.Single(candidate => + ReferenceEquals(candidate.InputParameter, parameter)).Name); + } + var settings = client.ClientSettings!; + Assert.AreEqual(name, settings.OtherRequiredParams.Single().Name); + Assert.IsTrue(settings.Properties.Any(property => property.Name == propertyName)); + } + [TestCase(false)] [TestCase(true)] public async Task ExperimentalCustomConfigurationBindingsUseContainingExperimentalContext(bool generatedModel) diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/RestClientProviders/RestClientProviderTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/RestClientProviders/RestClientProviderTests.cs index 905787d22df..d4778c67034 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/RestClientProviders/RestClientProviderTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/RestClientProviders/RestClientProviderTests.cs @@ -7,6 +7,8 @@ using System.Reflection; using System.Threading.Tasks; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.TypeSpec.Generator.ClientModel.Providers; using Microsoft.TypeSpec.Generator.Expressions; using Microsoft.TypeSpec.Generator.Input; @@ -118,6 +120,123 @@ public void NormalizedDateTimeOperationParameterIsSerialized( StringAssert.Contains(expectedSerialization, methodText); } + [Test] + public async Task AcronymNamedArgumentsFollowReorderedProtocolSignature( + [Values("New", "Published", "Custom")] string signatureSource) + { + var operation = InputFactory.Operation( + "Send", + parameters: + [ + InputFactory.PathParameter("version", InputPrimitiveType.String, isRequired: false), + InputFactory.QueryParameter("sourceIpAddress", InputPrimitiveType.String, isRequired: true) + ], + uri: "/things/{version}", + responses: [InputFactory.OperationResponse([204])]); + var serviceMethod = InputFactory.BasicServiceMethod( + "Send", operation, + parameters: [InputFactory.MethodParameter("sourceIpAddress", InputPrimitiveType.String, isRequired: true, location: InputRequestLocation.Query)]); + var inputClient = InputFactory.Client("TestClient", methods: [serviceMethod]); + var generator = await MockHelpers.LoadMockGeneratorAsync( + clients: () => [inputClient], + compilation: signatureSource == "Custom" ? async () => await Helpers.GetCompilationFromDirectoryAsync("Custom") : null, + lastContractCompilation: signatureSource == "Published" ? async () => await Helpers.GetCompilationFromDirectoryAsync("Published") : null); + var client = generator.Object.OutputLibrary.TypeProviders.OfType().Single(); + client.ProcessTypeForBackCompatibility(); + + var createRequest = client.RestClient.GetCreateRequestMethod(operation); + CollectionAssert.AreEqual( + new[] { "version", "sourceIPAddress", "options" }, + createRequest.Signature.Parameters.Select(parameter => parameter.Name)); + Assert.IsTrue(createRequest.Signature.Parameters.All(parameter => parameter.DefaultValue is null)); + + var requestSyntax = CSharpSyntaxTree.ParseText(createRequest.BodyStatements!.ToDisplayString()).GetRoot(); + var query = requestSyntax.DescendantNodes().OfType().Single(invocation => + invocation.Expression is MemberAccessExpressionSyntax member && member.Name.Identifier.ValueText == "AppendQuery"); + Assert.AreEqual("sourceIpAddress", ((LiteralExpressionSyntax)query.ArgumentList.Arguments[0].Expression).Token.ValueText); + Assert.AreEqual("sourceIPAddress", query.ArgumentList.Arguments[1].Expression.ToString()); + + var expectedName = signatureSource switch + { + "Published" => "sourceIpAddress", + "Custom" => "customIpAddress", + _ => "sourceIPAddress" + }; + var methods = client.Methods.OfType().Where(m => m.Kind == ScmMethodKind.Convenience).ToArray(); + Assert.AreEqual(2, methods.Length); + foreach (var method in methods) + { + var protocolMethod = client.Methods.OfType().Single( + protocol => protocol.Kind == ScmMethodKind.Protocol && protocol.Signature.Name == method.Signature.Name); + var protocolSyntax = CSharpSyntaxTree.ParseText(protocolMethod.BodyStatements!.ToDisplayString()).GetRoot(); + var requestInvocation = protocolSyntax.DescendantNodes().OfType().Single(invocation => + invocation.Expression is MemberAccessExpressionSyntax member && member.Name.Identifier.ValueText == "CreateSendRequest"); + CollectionAssert.AreEqual( + new[] { "version", expectedName, "options" }, + requestInvocation.ArgumentList.Arguments.Select(argument => argument.Expression.ToString())); + + StringAssert.Contains( + $"this.{method.Signature.Name}({expectedName}, {(signatureSource == "Custom" ? "version: null, " : "")}options: cancellationToken.ToRequestOptions())", + method.BodyStatements!.ToDisplayString()); + if (signatureSource == "New") + { + CollectionAssert.AreEqual( + new[] { "sourceIPAddress", "version", "options" }, + protocolMethod.Signature.Parameters.Select(parameter => parameter.Name)); + Assert.AreEqual( + Helpers.GetExpectedFromFile(method.Signature.Name.EndsWith("Async") ? "Async" : "Sync"), + method.BodyStatements!.ToDisplayString()); + } + } + } + + [Test] + public void AcronymArgumentsFollowRequiredParameterOrder() + { + var operation = InputFactory.Operation( + "Send", + parameters: + [ + InputFactory.PathParameter("version", InputPrimitiveType.String, isRequired: false), + InputFactory.QueryParameter("sourceIpAddress", InputPrimitiveType.String, isRequired: true) + ], + uri: "/things/{version}", + responses: [InputFactory.OperationResponse([204])]); + var serviceMethod = InputFactory.BasicServiceMethod( + "Send", + operation, + parameters: + [ + InputFactory.MethodParameter("version", InputPrimitiveType.String, location: InputRequestLocation.Path), + InputFactory.MethodParameter("sourceIpAddress", InputPrimitiveType.String, isRequired: true, location: InputRequestLocation.Query) + ]); + var inputClient = InputFactory.Client("TestClient", methods: [serviceMethod]); + MockHelpers.LoadMockGenerator(clients: () => [inputClient]); + var client = ScmCodeModelGenerator.Instance.TypeFactory.CreateClient(inputClient)!; + var methods = client.Methods.OfType().ToArray(); + Assert.AreEqual(4, methods.Length); + + foreach (var method in methods) + { + var syntax = CSharpSyntaxTree.ParseText(method.BodyStatements!.ToDisplayString()).GetRoot(); + var targetName = method.Kind == ScmMethodKind.Protocol ? "CreateSendRequest" : method.Signature.Name; + var invocation = syntax.DescendantNodes().OfType().Single(candidate => + candidate.Expression is MemberAccessExpressionSyntax member && member.Name.Identifier.ValueText == targetName); + Assert.AreEqual(3, invocation.ArgumentList.Arguments.Count); + CollectionAssert.AreEqual( + method.Kind == ScmMethodKind.Protocol + ? new[] { "version", "sourceIPAddress" } + : new[] { "sourceIPAddress", "version" }, + invocation.ArgumentList.Arguments.Take(2).Select(argument => argument.Expression.ToString())); + if (method.Kind == ScmMethodKind.Protocol) + { + CollectionAssert.AreEqual( + new[] { "sourceIPAddress", "version", "options" }, + method.Signature.Parameters.Select(parameter => parameter.Name)); + } + } + } + [Test] public void CollidingNormalizedDateTimeOperationParametersAreSerialized() { diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/RestClientProviders/TestData/RestClientProviderTests/AcronymNamedArgumentsFollowReorderedProtocolSignature(Async).cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/RestClientProviders/TestData/RestClientProviderTests/AcronymNamedArgumentsFollowReorderedProtocolSignature(Async).cs new file mode 100644 index 00000000000..db8320c4d0a --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/RestClientProviders/TestData/RestClientProviderTests/AcronymNamedArgumentsFollowReorderedProtocolSignature(Async).cs @@ -0,0 +1,3 @@ +global::Sample.Argument.AssertNotNullOrEmpty(sourceIPAddress, nameof(sourceIPAddress)); + +return await this.SendAsync(sourceIPAddress, options: cancellationToken.ToRequestOptions()).ConfigureAwait(false); diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/RestClientProviders/TestData/RestClientProviderTests/AcronymNamedArgumentsFollowReorderedProtocolSignature(Custom)/TestClient.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/RestClientProviders/TestData/RestClientProviderTests/AcronymNamedArgumentsFollowReorderedProtocolSignature(Custom)/TestClient.cs new file mode 100644 index 00000000000..3862337b940 --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/RestClientProviders/TestData/RestClientProviderTests/AcronymNamedArgumentsFollowReorderedProtocolSignature(Custom)/TestClient.cs @@ -0,0 +1,15 @@ +using System.ClientModel; +using System.ClientModel.Primitives; +using System.Threading; +using System.Threading.Tasks; + +namespace Sample +{ + public partial class TestClient + { + public partial ClientResult Send(string customIpAddress, string version, RequestOptions options); + public partial Task SendAsync(string customIpAddress, string version, RequestOptions options); + public partial ClientResult Send(string customIpAddress, CancellationToken cancellationToken); + public partial Task SendAsync(string customIpAddress, CancellationToken cancellationToken); + } +} diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/RestClientProviders/TestData/RestClientProviderTests/AcronymNamedArgumentsFollowReorderedProtocolSignature(Published)/TestClient.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/RestClientProviders/TestData/RestClientProviderTests/AcronymNamedArgumentsFollowReorderedProtocolSignature(Published)/TestClient.cs new file mode 100644 index 00000000000..8b82a048210 --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/RestClientProviders/TestData/RestClientProviderTests/AcronymNamedArgumentsFollowReorderedProtocolSignature(Published)/TestClient.cs @@ -0,0 +1,15 @@ +using System.ClientModel; +using System.ClientModel.Primitives; +using System.Threading; +using System.Threading.Tasks; + +namespace Sample +{ + public partial class TestClient + { + public virtual ClientResult Send(string sourceIpAddress, string version = null, RequestOptions options = null) => default; + public virtual Task SendAsync(string sourceIpAddress, string version = null, RequestOptions options = null) => default; + public virtual ClientResult Send(string sourceIpAddress, CancellationToken cancellationToken = default) => default; + public virtual Task SendAsync(string sourceIpAddress, CancellationToken cancellationToken = default) => default; + } +} diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/RestClientProviders/TestData/RestClientProviderTests/AcronymNamedArgumentsFollowReorderedProtocolSignature(Sync).cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/RestClientProviders/TestData/RestClientProviderTests/AcronymNamedArgumentsFollowReorderedProtocolSignature(Sync).cs new file mode 100644 index 00000000000..70d9cdeff4a --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/RestClientProviders/TestData/RestClientProviderTests/AcronymNamedArgumentsFollowReorderedProtocolSignature(Sync).cs @@ -0,0 +1,3 @@ +global::Sample.Argument.AssertNotNullOrEmpty(sourceIPAddress, nameof(sourceIPAddress)); + +return this.Send(sourceIPAddress, options: cancellationToken.ToRequestOptions()); diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ScmMethodProviderCollectionTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ScmMethodProviderCollectionTests.cs index c412697adb2..6791e01b607 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ScmMethodProviderCollectionTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/ScmMethodProviderCollectionTests.cs @@ -15,6 +15,7 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.TypeSpec.Generator.ClientModel.Primitives; using Microsoft.TypeSpec.Generator.ClientModel.Providers; using Microsoft.TypeSpec.Generator.EmitterRpc; using Microsoft.TypeSpec.Generator.Expressions; @@ -981,6 +982,548 @@ public async Task ConvenienceMethodForwardsNormalizedDateParameter() writer.ToString(false)); } + [Test] + public void BuildingProtocolSignaturesDoesNotMutateFactoryParameters() + { + var createdParameters = new List(); + bool captureParameters = false; + var operation = InputFactory.Operation( + "Send", + parameters: [InputFactory.QueryParameter("sourceIpAddress", InputPrimitiveType.Int32)], + responses: [InputFactory.OperationResponse([204])]); + var serviceMethod = InputFactory.BasicServiceMethod( + "Send", operation, + parameters: [InputFactory.MethodParameter("sourceIpAddress", InputPrimitiveType.Int32, location: InputRequestLocation.Query)]); + var inputClient = InputFactory.Client("TestClient", methods: [serviceMethod]); + MockHelpers.LoadMockGenerator( + clients: () => [inputClient], + createParameterCore: input => + { + var parameter = new ParameterProvider(input); + if (captureParameters && input.Name == "sourceIpAddress") + { + createdParameters.Add(parameter.ToPublicInputParameter()); + } + return parameter; + }); + var client = ScmCodeModelGenerator.Instance.TypeFactory.CreateClient(inputClient)!; + _ = client.RestClient.Methods; + captureParameters = true; + var methods = client.Methods.OfType().ToArray(); + + Assert.AreEqual(4, methods.Length); + Assert.IsNotEmpty(createdParameters); + foreach (var parameter in createdParameters) + { + Assert.AreEqual("sourceIPAddress", parameter.Name); + Assert.IsNotNull(parameter.DefaultValue); + Assert.IsTrue(parameter.Type.IsNullable); + } + foreach (var method in methods.Where(method => method.Kind == ScmMethodKind.Protocol)) + { + Assert.IsNull(method.Signature.Parameters[0].DefaultValue); + Assert.IsTrue(method.Signature.Parameters[0].Type.IsNullable); + } + } + + [Test] + public void KnownSignatureParametersRemainStable() + { + MockHelpers.LoadMockGenerator(); + Assert.AreSame(ScmKnownParameters.RequestOptions, ScmKnownParameters.RequestOptions); + Assert.AreSame(ScmKnownParameters.OptionalRequestOptions, ScmKnownParameters.OptionalRequestOptions); + Assert.AreSame(ScmKnownParameters.CancellationToken, ScmKnownParameters.CancellationToken); + Assert.AreSame(ScmKnownParameters.ContentType, ScmKnownParameters.ContentType); + Assert.AreSame(ScmKnownParameters.OptionalContentType, ScmKnownParameters.OptionalContentType); + } + + [Test] + public async Task PublishedCancellationTokenNamesDoNotAffectOtherMethods() + { + var serviceMethods = new[] { "Send", "Receive", "New" }.Select(name => InputFactory.BasicServiceMethod( + name, InputFactory.Operation(name, responses: [InputFactory.OperationResponse([204])]))).ToArray(); + var inputClient = InputFactory.Client("TestClient", methods: serviceMethods); + await MockHelpers.LoadMockGeneratorAsync( + clients: () => [inputClient], + lastContractCompilation: async () => await Helpers.GetCompilationFromDirectoryAsync()); + var client = ScmCodeModelGenerator.Instance.TypeFactory.CreateClient(inputClient)!; + client.ProcessTypeForBackCompatibility(); + var methods = client.Methods.OfType().Where(method => method.Kind == ScmMethodKind.Convenience).ToArray(); + Assert.AreEqual(6, methods.Length); + + foreach (var method in methods) + { + var expectedToken = method.Signature.Name switch + { + "Send" => "sendToken", + "SendAsync" => "sendAsyncToken", + "Receive" => "receiveToken", + "ReceiveAsync" => "receiveAsyncToken", + _ => "cancellationToken" + }; + var token = method.Signature.Parameters.Single(); + Assert.AreEqual(expectedToken, token.Name); + Assert.AreEqual(expectedToken, token.AsVariable().Declaration.RequestedName); + Assert.IsNotNull(token.DefaultValue); + StringAssert.Contains( + $"this.{method.Signature.Name}({expectedToken}.ToRequestOptions())", + method.BodyStatements!.ToDisplayString()); + } + Assert.AreEqual("cancellationToken", ScmKnownParameters.CancellationToken.Name); + } + + [Test] + public async Task MultipartContentTypeUsesWireNameAfterParameterRename( + [Values("Custom", "LastContract")] string signatureSource, + [Values(false, true)] bool bodyIsRequired) + { + var model = InputFactory.Model( + "UploadBody", + usage: InputModelTypeUsage.Input | InputModelTypeUsage.MultipartFormData, + properties: [InputFactory.Property("message", InputPrimitiveType.String, isRequired: true, + serializationOptions: InputFactory.Serialization.Options( + multipart: InputFactory.Serialization.Multipart("message", isFilePart: false, defaultContentTypes: ["text/plain"])))]); + var operation = InputFactory.Operation( + "Send", + parameters: + [ + InputFactory.ContentTypeParameter("multipart/form-data"), + InputFactory.BodyParameter("body", model, isRequired: bodyIsRequired, + contentTypes: ["multipart/form-data"], defaultContentType: "multipart/form-data") + ], + requestMediaTypes: ["multipart/form-data"], + responses: [InputFactory.OperationResponse([204])]); + var serviceMethod = InputFactory.BasicServiceMethod( + "Send", operation, + parameters: [InputFactory.MethodParameter("body", model, isRequired: bodyIsRequired)]); + var inputClient = InputFactory.Client("TestClient", methods: [serviceMethod]); + await MockHelpers.LoadMockGeneratorAsync( + clients: () => [inputClient], inputModels: () => [model], + compilation: signatureSource == "Custom" ? async () => await Helpers.GetCompilationFromDirectoryAsync("Custom") : null, + lastContractCompilation: signatureSource == "LastContract" ? async () => await Helpers.GetCompilationFromDirectoryAsync("LastContract") : null); + var client = ScmCodeModelGenerator.Instance.TypeFactory.CreateClient(inputClient)!; + client.ProcessTypeForBackCompatibility(); + var methods = client.Methods.OfType().Where(method => method.Kind == ScmMethodKind.Convenience).ToArray(); + Assert.AreEqual(2, methods.Length); + + foreach (var method in methods) + { + var protocol = client.Methods.OfType().Single(candidate => + candidate.Kind == ScmMethodKind.Protocol && candidate.Signature.Name == method.Signature.Name); + var expectedMediaTypeName = method.Signature.Name.EndsWith("Async", StringComparison.Ordinal) ? "asyncMediaType" : "mediaType"; + Assert.AreEqual(expectedMediaTypeName, protocol.Signature.Parameters[1].Name); + Assert.AreEqual("Content-Type", protocol.Signature.Parameters[1].WireInfo.SerializedName); + var syntax = CSharpSyntaxTree.ParseText(method.BodyStatements!.ToDisplayString()).GetRoot(); + var invocation = syntax.DescendantNodes().OfType().Single(candidate => + candidate.Expression is MemberAccessExpressionSyntax member && member.Name.Identifier.ValueText == protocol.Signature.Name); + CollectionAssert.AreEqual( + new[] { "content", bodyIsRequired ? "content.MediaType" : "content?.MediaType", "cancellationToken.ToRequestOptions()" }, + invocation.ArgumentList.Arguments.Select(argument => argument.Expression.ToString())); + } + } + + [Test] + public async Task OptionalMultipartLegacyParameterOrderIsPreserved( + [Values("Custom", "LastContract")] string signatureSource) + { + var model = InputFactory.Model( + "UploadBody", + usage: InputModelTypeUsage.Input | InputModelTypeUsage.MultipartFormData, + properties: [InputFactory.Property("message", InputPrimitiveType.String, isRequired: true, + serializationOptions: InputFactory.Serialization.Options( + multipart: InputFactory.Serialization.Multipart("message", isFilePart: false, defaultContentTypes: ["text/plain"])))]); + var operation = InputFactory.Operation( + "Send", + parameters: + [ + InputFactory.ContentTypeParameter("multipart/form-data"), + InputFactory.BodyParameter("body", model, + contentTypes: ["multipart/form-data"], defaultContentType: "multipart/form-data") + ], + requestMediaTypes: ["multipart/form-data"], + responses: [InputFactory.OperationResponse([204])]); + var serviceMethod = InputFactory.BasicServiceMethod( + "Send", operation, parameters: [InputFactory.MethodParameter("body", model)]); + var inputClient = InputFactory.Client("TestClient", methods: [serviceMethod]); + await MockHelpers.LoadMockGeneratorAsync( + clients: () => [inputClient], inputModels: () => [model], + compilation: signatureSource == "Custom" ? async () => await Helpers.GetCompilationFromDirectoryAsync("Custom") : null, + lastContractCompilation: signatureSource == "LastContract" ? async () => await Helpers.GetCompilationFromDirectoryAsync("LastContract") : null); + var client = ScmCodeModelGenerator.Instance.TypeFactory.CreateClient(inputClient)!; + client.ProcessTypeForBackCompatibility(); + var methods = client.Methods.OfType().Where(method => method.Kind == ScmMethodKind.Protocol).ToArray(); + Assert.AreEqual(2, methods.Length); + + foreach (var method in methods) + { + var isAsync = method.Signature.Name.EndsWith("Async", StringComparison.Ordinal); + Assert.AreEqual(signatureSource == "Custom", method.IsPartialMethod); + Assert.IsTrue(method.Signature.Parameters[0].Type.Equals(isAsync ? typeof(string) : typeof(BinaryContent))); + Assert.IsTrue(method.Signature.Parameters[1].Type.Equals(isAsync ? typeof(BinaryContent) : typeof(string))); + var protocolSyntax = CSharpSyntaxTree.ParseText(method.BodyStatements!.ToDisplayString()).GetRoot(); + var requestInvocation = protocolSyntax.DescendantNodes().OfType().Single(candidate => + candidate.Expression is MemberAccessExpressionSyntax member && member.Name.Identifier.ValueText == "CreateSendRequest"); + CollectionAssert.AreEqual( + new[] { method.Signature.Parameters[isAsync ? 1 : 0].Name, method.Signature.Parameters[isAsync ? 0 : 1].Name, method.Signature.Parameters[^1].Name }, + requestInvocation.ArgumentList.Arguments.Select(argument => argument.Expression.ToString())); + var convenience = client.Methods.OfType().Single(candidate => + candidate.Kind == ScmMethodKind.Convenience && candidate.Signature.Name == method.Signature.Name); + var syntax = CSharpSyntaxTree.ParseText(convenience.BodyStatements!.ToDisplayString()).GetRoot(); + var invocation = syntax.DescendantNodes().OfType().Single(candidate => + candidate.Expression is MemberAccessExpressionSyntax member && member.Name.Identifier.ValueText == method.Signature.Name); + CollectionAssert.AreEqual( + isAsync + ? new[] { "content?.MediaType", "content", "cancellationToken.ToRequestOptions()" } + : new[] { "content", "content?.MediaType", "cancellationToken.ToRequestOptions()" }, + invocation.ArgumentList.Arguments.Select(argument => argument.Expression.ToString())); + } + } + + [Test] + public void MethodSignatureParametersAreIndependent() + { + var operations = new[] { "Send", "Receive" }.Select(name => InputFactory.Operation( + name, + parameters: [InputFactory.QueryParameter("sourceIpAddress", InputPrimitiveType.String, isRequired: true)], + responses: [InputFactory.OperationResponse([204])])).ToArray(); + var serviceMethods = operations.Select(operation => InputFactory.BasicServiceMethod( + operation.Name, + operation, + parameters: [InputFactory.MethodParameter("sourceIpAddress", InputPrimitiveType.String, isRequired: true, location: InputRequestLocation.Query)])).ToArray(); + var inputClient = InputFactory.Client("TestClient", methods: serviceMethods); + MockHelpers.LoadMockGenerator(clients: () => [inputClient]); + var client = ScmCodeModelGenerator.Instance.TypeFactory.CreateClient(inputClient)!; + var methods = client.Methods.OfType() + .Concat(client.RestClient.Methods.OfType()).ToArray(); + Assert.AreEqual(10, methods.Length); + + for (int i = 0; i < methods.Length; i++) + { + for (int j = i + 1; j < methods.Length; j++) + { + Assert.AreNotSame(methods[i].Signature.Parameters[0], methods[j].Signature.Parameters[0]); + Assert.AreNotSame(methods[i].Signature.Parameters[^1], methods[j].Signature.Parameters[^1]); + } + } + + var protocol = methods.Single(method => method.Kind == ScmMethodKind.Protocol && method.Signature.Name == "Send"); + protocol.Signature.Parameters[0].Update(name: "publishedIpAddress"); + protocol.Signature.Parameters[^1].Update(name: "publishedOptions"); + foreach (var method in methods.Where(method => !ReferenceEquals(method, protocol))) + { + Assert.AreEqual("sourceIPAddress", method.Signature.Parameters[0].Name); + Assert.AreEqual( + method.Kind == ScmMethodKind.Convenience ? "cancellationToken" : "options", + method.Signature.Parameters[^1].Name); + } + } + + [Test] + public async Task AcronymOperationParameterNames( + [Values("sourceIpAddress", "targetDbName", "guestOsType", "IPv4Address", "IPv6Address")] string inputName, + [Values(InputRequestLocation.Query, InputRequestLocation.Path, InputRequestLocation.Header, InputRequestLocation.Body)] InputRequestLocation location, + [Values(false, true)] bool isExactName) + { + var expectedName = isExactName ? inputName : inputName switch + { + "sourceIpAddress" => "sourceIPAddress", + "targetDbName" => "targetDBName", + "guestOsType" => "guestOSType", + "IPv4Address" => "ipv4Address", + "IPv6Address" => "ipv6Address", + _ => throw new InvalidOperationException() + }; + const string wireName = "wire-name"; + InputParameter parameter = location switch + { + InputRequestLocation.Query => InputFactory.QueryParameter(inputName, InputPrimitiveType.String, isRequired: true, serializedName: wireName), + InputRequestLocation.Path => InputFactory.PathParameter(inputName, InputPrimitiveType.String, isRequired: true, serializedName: wireName), + InputRequestLocation.Header => InputFactory.HeaderParameter(inputName, InputPrimitiveType.String, isRequired: true, serializedName: wireName), + InputRequestLocation.Body => InputFactory.BodyParameter(inputName, InputPrimitiveType.String, isRequired: true), + _ => throw new InvalidOperationException() + }; + typeof(InputProperty).GetProperty(nameof(InputProperty.IsExactName))!.SetValue(parameter, isExactName); + var operation = InputFactory.Operation( + "Send", + parameters: [parameter], + uri: location == InputRequestLocation.Path ? "/things/{wire-name}" : "", + responses: [InputFactory.OperationResponse([204])]); + var serviceMethod = InputFactory.BasicServiceMethod( + "Send", + operation, + parameters: [InputFactory.MethodParameter(inputName, InputPrimitiveType.String, isRequired: true, location: location, isExactName: isExactName)]); + var inputClient = InputFactory.Client("TestClient", methods: [serviceMethod]); + await MockHelpers.LoadMockGeneratorAsync( + clients: () => [inputClient], + configuration: """{"disable-xml-docs": false, "package-name": "Sample"}"""); + var client = ScmCodeModelGenerator.Instance.TypeFactory.CreateClient(inputClient)!; + var methods = new ScmMethodProviderCollection(serviceMethod, client); + Assert.AreEqual(4, methods.Count); + + foreach (var method in methods) + { + var isProtocol = method.Kind == ScmMethodKind.Protocol; + var emittedName = isProtocol && location == InputRequestLocation.Body ? "content" : expectedName; + Assert.AreEqual(emittedName, method.Signature.Parameters[0].Name); + using var writer = new CodeWriter(); + writer.WriteMethod(method); + var text = writer.ToString(false); + StringAssert.Contains($"", text); + StringAssert.Contains($"", text); + StringAssert.Contains($"nameof({emittedName})", text); + if (isProtocol) + { + StringAssert.Contains($"CreateSendRequest({emittedName}, options)", text); + } + else if (location == InputRequestLocation.Body) + { + StringAssert.Contains($"FromString({expectedName})", text); + } + else + { + StringAssert.Contains($"this.{method.Signature.Name}({expectedName}, cancellationToken.ToRequestOptions())", text); + } + } + + var request = client.RestClient.Methods.Single(); + Assert.AreEqual(location == InputRequestLocation.Body ? "content" : expectedName, request.Signature.Parameters[0].Name); + using var requestWriter = new CodeWriter(); + requestWriter.WriteMethod(request); + var requestText = requestWriter.ToString(false); + var expectedSerialization = location switch + { + InputRequestLocation.Query => $"uri.AppendQuery(\"{wireName}\", {expectedName},", + InputRequestLocation.Path => $"uri.AppendPath({expectedName},", + InputRequestLocation.Header => $"request.Headers.Set(\"{wireName}\", {expectedName})", + InputRequestLocation.Body => "request.Content = content;", + _ => throw new InvalidOperationException() + }; + StringAssert.Contains(expectedSerialization, requestText); + } + + [Test] + public async Task AcronymSpreadParameterReferences() + { + var model = InputFactory.Model( + "Network", + usage: InputModelTypeUsage.Spread, + properties: + [ + InputFactory.Property("sourceIpAddress", InputPrimitiveType.String, isRequired: true), + InputFactory.Property("targetDbName", InputPrimitiveType.String, isRequired: true), + InputFactory.Property("guestOsType", InputPrimitiveType.String, isRequired: true) + ]); + var operation = InputFactory.Operation( + "Send", + parameters: [InputFactory.BodyParameter("network", model, isRequired: true, scope: InputParameterScope.Spread)], + responses: [InputFactory.OperationResponse([204])]); + var serviceMethod = InputFactory.BasicServiceMethod( + "Send", + operation, + parameters: + [ + InputFactory.MethodParameter("sourceIpAddress", InputPrimitiveType.String, isRequired: true, scope: InputParameterScope.Spread), + InputFactory.MethodParameter("targetDbName", InputPrimitiveType.String, isRequired: true, scope: InputParameterScope.Spread), + InputFactory.MethodParameter("guestOsType", InputPrimitiveType.String, isRequired: true, scope: InputParameterScope.Spread) + ]); + var inputClient = InputFactory.Client("TestClient", methods: [serviceMethod]); + await MockHelpers.LoadMockGeneratorAsync(clients: () => [inputClient], inputModels: () => [model]); + var client = ScmCodeModelGenerator.Instance.TypeFactory.CreateClient(inputClient)!; + var methods = new ScmMethodProviderCollection(serviceMethod, client); + var convenienceMethods = methods.Where(method => method.Kind == ScmMethodKind.Convenience).ToArray(); + Assert.AreEqual(2, convenienceMethods.Length); + foreach (var method in convenienceMethods) + { + CollectionAssert.AreEqual( + new[] { "sourceIPAddress", "targetDBName", "guestOSType" }, + method.Signature.Parameters.Take(3).Select(parameter => parameter.Name)); + StringAssert.Contains( + "new global::Sample.Models.Network(sourceIPAddress, targetDBName, guestOSType, default)", + method.BodyStatements!.ToDisplayString()); + } + } + + [Test] + public async Task AcronymSpreadParametersPreserveSignatures( + [Values("Normalized", "Exact", "Custom", "LastContract")] string signatureSource) + { + string[] inputNames = ["targetDbName", "sourceIpAddress", "guestOsType"]; + string[] wireNames = ["target-db", "source-ip", "guest-os"]; + var model = InputFactory.Model( + "Network", + usage: InputModelTypeUsage.Spread, + properties: + [ + InputFactory.Property("sourceIpAddress", InputPrimitiveType.String, isRequired: true, wireName: wireNames[1]), + InputFactory.Property("targetDbName", InputPrimitiveType.String, isRequired: true, wireName: wireNames[0]), + InputFactory.Property("guestOsType", InputPrimitiveType.String, wireName: wireNames[2]) + ]); + var operation = InputFactory.Operation( + "Send", + parameters: [InputFactory.BodyParameter("network", model, isRequired: true, scope: InputParameterScope.Spread)], + responses: [InputFactory.OperationResponse([204])]); + var serviceMethod = InputFactory.BasicServiceMethod( + "Send", + operation, + parameters: inputNames.Select((name, index) => InputFactory.MethodParameter( + name, InputPrimitiveType.String, isRequired: index < 2, scope: InputParameterScope.Spread, + serializedName: wireNames[index], isExactName: signatureSource == "Exact")).ToArray()); + var inputClient = InputFactory.Client("TestClient", methods: [serviceMethod]); + await MockHelpers.LoadMockGeneratorAsync( + clients: () => [inputClient], + inputModels: () => [model], + compilation: signatureSource == "Custom" ? async () => await Helpers.GetCompilationFromDirectoryAsync("Custom") : null, + lastContractCompilation: signatureSource == "LastContract" ? async () => await Helpers.GetCompilationFromDirectoryAsync("LastContract") : null); + var client = ScmCodeModelGenerator.Instance.TypeFactory.CreateClient(inputClient)!; + client.ProcessTypeForBackCompatibility(); + var methods = client.Methods.OfType().ToArray(); + Assert.AreEqual(4, methods.Length); + + foreach (var method in methods) + { + var body = method.BodyStatements!.ToDisplayString(); + if (method.Kind == ScmMethodKind.Protocol) + { + CollectionAssert.AreEqual(new[] { "content", "options" }, method.Signature.Parameters.Select(parameter => parameter.Name)); + StringAssert.Contains("this.CreateSendRequest(content, options)", body); + continue; + } + + var suffix = method.Signature.Name.EndsWith("Async", StringComparison.Ordinal) ? "Async" : "Sync"; + string[] expectedNames = signatureSource switch + { + "Exact" => inputNames, + "Custom" => [$"customDbName{suffix}", $"customIpAddress{suffix}", $"customOsType{suffix}"], + "LastContract" => [$"publishedDbName{suffix}", $"publishedIpAddress{suffix}", $"publishedOsType{suffix}"], + _ => ["targetDBName", "sourceIPAddress", "guestOSType"] + }; + var expectedToken = signatureSource switch + { + "Custom" => $"customToken{suffix}", + "LastContract" => $"publishedToken{suffix}", + _ => "cancellationToken" + }; + CollectionAssert.AreEqual(expectedNames, method.Signature.Parameters.Take(3).Select(parameter => parameter.Name)); + CollectionAssert.AreEqual(wireNames, method.Signature.Parameters.Take(3).Select(parameter => parameter.WireInfo.SerializedName)); + Assert.IsTrue(method.Signature.Parameters.Take(3).All(parameter => parameter.SpreadSource != null)); + Assert.AreEqual(signatureSource == "Custom", method.IsPartialMethod); + Assert.AreEqual(signatureSource != "Custom", method.Signature.Parameters[2].DefaultValue != null); + + var syntax = CSharpSyntaxTree.ParseText(body).GetRoot(); + var construction = syntax.DescendantNodes().OfType().Single(expression => + expression.Type.ToString().EndsWith(".Network", StringComparison.Ordinal)); + CollectionAssert.AreEqual( + new[] { expectedNames[1], expectedNames[0], expectedNames[2], "default" }, + construction.ArgumentList!.Arguments.Select(argument => argument.Expression.ToString())); + StringAssert.Contains($"this.{method.Signature.Name}(spreadModel, {expectedToken}.ToRequestOptions())", body); + } + + CollectionAssert.AreEqual(inputNames, serviceMethod.Parameters.Select(parameter => parameter.Name)); + CollectionAssert.AreEqual(new[] { "content", "options" }, client.RestClient.Methods.Single().Signature.Parameters.Select(parameter => parameter.Name)); + } + + [Test] + public void PagingAndStreamingArgumentsFollowCreateRequestSignature( + [Values(false, true)] bool isStreaming, + [Values(false, true)] bool omitPathParameter) + { + var item = InputFactory.Model("Item", properties: [InputFactory.Property("name", InputPrimitiveType.String)]); + var page = InputFactory.Model("Page", properties: [InputFactory.Property("items", InputFactory.Array(item))]); + InputType responseType = isStreaming + ? new InputStreamingType("JsonlStream", "Streaming.Jsonl.JsonlStream", item, ["application/jsonl"]) + : page; + var operation = InputFactory.Operation( + "Receive", + parameters: + [ + InputFactory.PathParameter("targetDbName", InputPrimitiveType.String, serializedName: "db-name"), + InputFactory.QueryParameter("sourceIpAddress", InputPrimitiveType.String, isRequired: true, serializedName: "ip-address") + ], + uri: "/networks/{db-name}", + responses: [InputFactory.OperationResponse([200], responseType)], + bufferResponse: !isStreaming); + var methodParameters = new List(); + if (!omitPathParameter) + { + methodParameters.Add(InputFactory.MethodParameter( + "targetDbName", InputPrimitiveType.String, location: InputRequestLocation.Path, serializedName: "db-name")); + } + methodParameters.Add(InputFactory.MethodParameter( + "sourceIpAddress", InputPrimitiveType.String, isRequired: true, location: InputRequestLocation.Query, serializedName: "ip-address")); + InputServiceMethod serviceMethod = isStreaming + ? InputFactory.BasicServiceMethod( + "Receive", operation, parameters: methodParameters, response: InputFactory.ServiceMethodResponse(responseType, null)) + : InputFactory.PagingServiceMethod( + "Receive", operation, parameters: methodParameters, response: InputFactory.ServiceMethodResponse(responseType, null), + pagingMetadata: InputFactory.PagingMetadata(["items"], null, null)); + var inputClient = InputFactory.Client("TestClient", methods: [serviceMethod]); + MockHelpers.LoadMockGenerator(clients: () => [inputClient], inputModels: () => [item, page]); + var client = ScmCodeModelGenerator.Instance.TypeFactory.CreateClient(inputClient)!; + var methods = client.Methods.OfType().Where(method => method.Kind == ScmMethodKind.Convenience).ToArray(); + Assert.AreEqual(isStreaming ? 1 : 2, methods.Length); + + var request = client.RestClient.GetCreateRequestMethod(operation); + CollectionAssert.AreEqual( + new[] { "targetDBName", "sourceIPAddress", "options" }, + request.Signature.Parameters.Select(parameter => parameter.Name)); + Assert.IsTrue(request.Signature.Parameters.All(parameter => parameter.DefaultValue is null)); + + foreach (var method in methods) + { + var syntax = CSharpSyntaxTree.ParseText(method.BodyStatements!.ToDisplayString()).GetRoot(); + var arguments = isStreaming + ? syntax.DescendantNodes().OfType().Single(invocation => + invocation.Expression is MemberAccessExpressionSyntax member && member.Name.Identifier.ValueText == request.Signature.Name).ArgumentList.Arguments + : syntax.DescendantNodes().OfType().Single(construction => + construction.Type.ToString().Contains("CollectionResult", StringComparison.Ordinal)).ArgumentList!.Arguments; + CollectionAssert.AreEqual( + new[] { omitPathParameter ? "null" : "targetDBName", "sourceIPAddress", "cancellationToken.ToRequestOptions()" }, + arguments.Skip(isStreaming ? 0 : 1).Select(argument => argument.Expression.ToString())); + CollectionAssert.AreEqual( + omitPathParameter ? new[] { "targetDBName", "sourceIPAddress", "options" } : new string?[] { null, null, null }, + arguments.Skip(isStreaming ? 0 : 1).Select(argument => argument.NameColon?.Name.Identifier.ValueText)); + } + } + + [Test] + public async Task AcronymGroupedParameterReferences() + { + var optionsModel = InputFactory.Model( + "NetworkOptions", + properties: [InputFactory.Property("sourceIpAddress", InputPrimitiveType.String, isRequired: true, isHttpMetadata: true, wireName: "source-ip")]); + var query = InputFactory.QueryParameter("sourceIpAddress", InputPrimitiveType.String, isRequired: true, serializedName: "source-ip"); + query.Update(methodParameterSegments: + [ + InputFactory.MethodParameter("targetDbOptions", optionsModel, isRequired: true, location: InputRequestLocation.Query), + InputFactory.MethodParameter("sourceIpAddress", InputPrimitiveType.String, isRequired: true) + ]); + var operation = InputFactory.Operation("Send", parameters: [query], responses: [InputFactory.OperationResponse([204])]); + var serviceMethod = InputFactory.BasicServiceMethod( + "Send", + operation, + parameters: [InputFactory.MethodParameter("targetDbOptions", optionsModel, isRequired: true, location: InputRequestLocation.Query)]); + var inputClient = InputFactory.Client("TestClient", methods: [serviceMethod]); + await MockHelpers.LoadMockGeneratorAsync(clients: () => [inputClient], inputModels: () => [optionsModel]); + var client = ScmCodeModelGenerator.Instance.TypeFactory.CreateClient(inputClient)!; + var methods = new ScmMethodProviderCollection(serviceMethod, client); + Assert.AreEqual(4, methods.Count); + foreach (var method in methods) + { + Assert.AreEqual("targetDBOptions", method.Signature.Parameters[0].Name); + var body = method.BodyStatements!.ToDisplayString(); + StringAssert.Contains("nameof(targetDBOptions)", body); + StringAssert.Contains( + method.Kind == ScmMethodKind.Protocol + ? "this.CreateSendRequest(targetDBOptions.SourceIPAddress," + : $"this.{method.Signature.Name}(targetDBOptions,", + body); + } + var request = client.RestClient.Methods.Single(); + using var writer = new CodeWriter(); + writer.WriteMethod(request); + StringAssert.Contains("uri.AppendQuery(\"source-ip\", sourceIPAddress,", writer.ToString(false)); + } + [Test] public void ListMethodWithNoPaging() { diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ScmMethodProviderCollectionTests/AcronymSpreadParametersPreserveSignatures(Custom)/TestClient.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ScmMethodProviderCollectionTests/AcronymSpreadParametersPreserveSignatures(Custom)/TestClient.cs new file mode 100644 index 00000000000..ac270a5e92e --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ScmMethodProviderCollectionTests/AcronymSpreadParametersPreserveSignatures(Custom)/TestClient.cs @@ -0,0 +1,15 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.ClientModel; +using System.Threading; +using System.Threading.Tasks; + +namespace Sample +{ + public partial class TestClient + { + public partial ClientResult Send(string customDbNameSync, string customIpAddressSync, string customOsTypeSync, CancellationToken customTokenSync); + public partial Task SendAsync(string customDbNameAsync, string customIpAddressAsync, string customOsTypeAsync, CancellationToken customTokenAsync); + } +} diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ScmMethodProviderCollectionTests/AcronymSpreadParametersPreserveSignatures(LastContract)/TestClient.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ScmMethodProviderCollectionTests/AcronymSpreadParametersPreserveSignatures(LastContract)/TestClient.cs new file mode 100644 index 00000000000..ad9c1cb4186 --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ScmMethodProviderCollectionTests/AcronymSpreadParametersPreserveSignatures(LastContract)/TestClient.cs @@ -0,0 +1,15 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.ClientModel; +using System.Threading; +using System.Threading.Tasks; + +namespace Sample +{ + public partial class TestClient + { + public virtual ClientResult Send(string publishedDbNameSync, string publishedIpAddressSync, string publishedOsTypeSync = default, CancellationToken publishedTokenSync = default) => default; + public virtual Task SendAsync(string publishedDbNameAsync, string publishedIpAddressAsync, string publishedOsTypeAsync = default, CancellationToken publishedTokenAsync = default) => default; + } +} diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ScmMethodProviderCollectionTests/MultipartContentTypeUsesWireNameAfterParameterRename(Custom)/TestClient.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ScmMethodProviderCollectionTests/MultipartContentTypeUsesWireNameAfterParameterRename(Custom)/TestClient.cs new file mode 100644 index 00000000000..38b6a6a760e --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ScmMethodProviderCollectionTests/MultipartContentTypeUsesWireNameAfterParameterRename(Custom)/TestClient.cs @@ -0,0 +1,15 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.ClientModel; +using System.ClientModel.Primitives; +using System.Threading.Tasks; + +namespace Sample +{ + public partial class TestClient + { + public partial ClientResult Send(BinaryContent payload, string mediaType, RequestOptions requestOptions); + public partial Task SendAsync(BinaryContent asyncPayload, string asyncMediaType, RequestOptions asyncOptions); + } +} diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ScmMethodProviderCollectionTests/MultipartContentTypeUsesWireNameAfterParameterRename(LastContract)/TestClient.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ScmMethodProviderCollectionTests/MultipartContentTypeUsesWireNameAfterParameterRename(LastContract)/TestClient.cs new file mode 100644 index 00000000000..c45891e6402 --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ScmMethodProviderCollectionTests/MultipartContentTypeUsesWireNameAfterParameterRename(LastContract)/TestClient.cs @@ -0,0 +1,15 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.ClientModel; +using System.ClientModel.Primitives; +using System.Threading.Tasks; + +namespace Sample +{ + public partial class TestClient + { + public virtual ClientResult Send(BinaryContent payload, string mediaType, RequestOptions requestOptions = default) => default; + public virtual Task SendAsync(BinaryContent asyncPayload, string asyncMediaType, RequestOptions asyncOptions = default) => default; + } +} diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ScmMethodProviderCollectionTests/OptionalMultipartLegacyParameterOrderIsPreserved(Custom)/TestClient.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ScmMethodProviderCollectionTests/OptionalMultipartLegacyParameterOrderIsPreserved(Custom)/TestClient.cs new file mode 100644 index 00000000000..3693262c30f --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ScmMethodProviderCollectionTests/OptionalMultipartLegacyParameterOrderIsPreserved(Custom)/TestClient.cs @@ -0,0 +1,15 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.ClientModel; +using System.ClientModel.Primitives; +using System.Threading.Tasks; + +namespace Sample +{ + public partial class TestClient + { + public partial ClientResult Send(BinaryContent payload, string mediaType, RequestOptions requestOptions); + public partial Task SendAsync(string asyncMediaType, BinaryContent asyncPayload, RequestOptions asyncOptions); + } +} diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ScmMethodProviderCollectionTests/OptionalMultipartLegacyParameterOrderIsPreserved(LastContract)/TestClient.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ScmMethodProviderCollectionTests/OptionalMultipartLegacyParameterOrderIsPreserved(LastContract)/TestClient.cs new file mode 100644 index 00000000000..686d5ac6a71 --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ScmMethodProviderCollectionTests/OptionalMultipartLegacyParameterOrderIsPreserved(LastContract)/TestClient.cs @@ -0,0 +1,15 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.ClientModel; +using System.ClientModel.Primitives; +using System.Threading.Tasks; + +namespace Sample +{ + public partial class TestClient + { + public virtual ClientResult Send(BinaryContent content, string contentType, RequestOptions options = default) => default; + public virtual Task SendAsync(string contentType, BinaryContent content, RequestOptions options = default) => default; + } +} diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ScmMethodProviderCollectionTests/PublishedCancellationTokenNamesDoNotAffectOtherMethods/TestClient.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ScmMethodProviderCollectionTests/PublishedCancellationTokenNamesDoNotAffectOtherMethods/TestClient.cs new file mode 100644 index 00000000000..5c9c275bcba --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/TestData/ScmMethodProviderCollectionTests/PublishedCancellationTokenNamesDoNotAffectOtherMethods/TestClient.cs @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.ClientModel; +using System.Threading; +using System.Threading.Tasks; + +namespace Sample +{ + public partial class TestClient + { + public virtual ClientResult Send(CancellationToken sendToken = default) => default; + public virtual Task SendAsync(CancellationToken sendAsyncToken = default) => default; + public virtual ClientResult Receive(CancellationToken receiveToken = default) => default; + public virtual Task ReceiveAsync(CancellationToken receiveAsyncToken = default) => default; + } +} diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Expressions/PositionalParameterReferenceExpression.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Expressions/PositionalParameterReferenceExpression.cs index 66a378868e7..c74d810cf2f 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Expressions/PositionalParameterReferenceExpression.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Expressions/PositionalParameterReferenceExpression.cs @@ -7,7 +7,22 @@ namespace Microsoft.TypeSpec.Generator.Expressions { public sealed record PositionalParameterReferenceExpression(string ParameterName, ValueExpression ParameterValue) : ValueExpression { - internal PositionalParameterReferenceExpression(ParameterProvider parameter) : this(parameter.Name, parameter) { } + // Back-compat restores the callee's name after the caller's arguments have been built. + private readonly ParameterProvider? _parameter; + private readonly string _parameterName = ParameterName; + + public string ParameterName + { + get => _parameter?.Name ?? _parameterName; + init => _parameterName = value; + } + + internal PositionalParameterReferenceExpression(ParameterProvider parameter) : this(parameter, parameter) { } + + internal PositionalParameterReferenceExpression(ParameterProvider parameter, ValueExpression value) : this(parameter.Name, value) + { + _parameter = parameter; + } internal override void Write(CodeWriter writer) { diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ParameterProvider.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ParameterProvider.cs index 085884e325e..b70ae57f2e7 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ParameterProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ParameterProvider.cs @@ -72,9 +72,18 @@ public sealed class ParameterProvider : IEquatable public ParameterProvider(InputParameter inputParameter) { InputParameter = inputParameter; - Name = !inputParameter.IsExactName && inputParameter.Type.IsDateTimeInputType() - ? inputParameter.Name.NormalizeDateTimeSuffix() - : inputParameter.Name; + Name = inputParameter.Name; + if (!inputParameter.IsExactName) + { + if (inputParameter.Type.IsDateTimeInputType()) + { + Name = Name.NormalizeDateTimeSuffix(); + } + if (inputParameter.Scope != InputParameterScope.Client) + { + Name = Name.NormalizeCSharpAcronyms(useCamelCase: true); + } + } Description = DocHelpers.GetFormattableDescription(inputParameter.Summary, inputParameter.Doc) ?? FormattableStringHelpers.Empty; var type = CodeModelGenerator.Instance.TypeFactory.CreateCSharpType(inputParameter.Type); if (type is null) 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 fe73f4bf19c..e5328171c92 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 @@ -5,6 +5,7 @@ using System.Diagnostics.CodeAnalysis; using System.Text; using Microsoft.TypeSpec.Generator.Input; +using Microsoft.TypeSpec.Generator.Input.Extensions; namespace Microsoft.TypeSpec.Generator.Utilities { @@ -21,7 +22,7 @@ private static readonly (string Source, string Replacement)[] _acronymRenamingRu ("Os", "OS") ]; - public static string NormalizeCSharpAcronyms(this string name, bool normalizeDateTimeSuffix = false) + public static string NormalizeCSharpAcronyms(this string name, bool normalizeDateTimeSuffix = false, bool useCamelCase = false) { name = normalizeDateTimeSuffix ? name.NormalizeDateTimeSuffix() : name; StringBuilder? normalizedName = null; @@ -30,7 +31,9 @@ public static string NormalizeCSharpAcronyms(this string name, bool normalizeDat { foreach (var rule in _acronymRenamingRules) { - if (!name.AsSpan(index).StartsWith(rule.Source, StringComparison.Ordinal)) + var isLeadingParameterAcronym = useCamelCase && index == 0; + if (!name.AsSpan(index).StartsWith(rule.Source, + isLeadingParameterAcronym ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal)) { continue; } @@ -43,7 +46,7 @@ public static string NormalizeCSharpAcronyms(this string name, bool normalizeDat normalizedName ??= new StringBuilder(name.Length); normalizedName.Append(name, segmentStart, index - segmentStart); - normalizedName.Append(rule.Replacement); + normalizedName.Append(isLeadingParameterAcronym ? rule.Replacement.ToVariableName() : rule.Replacement); segmentStart = boundaryIndex; index = boundaryIndex - 1; break; diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Shared/MethodSignatureHelper.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Shared/MethodSignatureHelper.cs index 5ea3e2058a2..6b5aedff937 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Shared/MethodSignatureHelper.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Shared/MethodSignatureHelper.cs @@ -10,6 +10,7 @@ using Microsoft.TypeSpec.Generator.Providers; using Microsoft.TypeSpec.Generator.Snippets; using Microsoft.TypeSpec.Generator.Statements; +using Microsoft.TypeSpec.Generator.Utilities; namespace Microsoft.TypeSpec.Generator { @@ -20,23 +21,74 @@ internal static bool IsPublicApi(MethodSignatureModifiers modifiers) && !modifiers.HasFlag(MethodSignatureModifiers.Private); internal static bool ContainsSameParameters(MethodSignature method1, MethodSignature method2) + => TryMatchParameterOrder(method2.Parameters, method1.Parameters, out _); + + internal static bool TryMatchParameterOrder( + IReadOnlyList currentParameters, + IReadOnlyList previousParameters, + out ParameterProvider[] matchedParameters) { - var count = method1.Parameters.Count; - if (count != method2.Parameters.Count) + matchedParameters = []; + if (currentParameters.Count != previousParameters.Count) { return false; } - HashSet method1Parameters = new(method1.Parameters, new ParameterProviderVariableNameComparer()); - foreach (var method2Param in method2.Parameters) + var inputNames = new Dictionary(StringComparer.Ordinal); + var declaredNames = new Dictionary(StringComparer.Ordinal); + var normalizedNames = new Dictionary(StringComparer.OrdinalIgnoreCase); + foreach (var parameter in currentParameters) { - if (!method1Parameters.Contains(method2Param)) + AddAlias(declaredNames, parameter.Name, parameter); + AddAlias(normalizedNames, NormalizeParameterName(parameter.Name), parameter); + if (parameter.InputParameter is { IsExactName: false } input) + { + AddAlias(inputNames, input.OriginalName, parameter); + AddAlias(inputNames, input.Name, parameter); + AddAlias(normalizedNames, NormalizeParameterName(input.OriginalName), parameter); + AddAlias(normalizedNames, NormalizeParameterName(input.Name), parameter); + } + } + + var ordered = new ParameterProvider[previousParameters.Count]; + var used = new HashSet(ReferenceEqualityComparer.Instance); + for (int i = 0; i < previousParameters.Count; i++) + { + var previous = previousParameters[i]; + inputNames.TryGetValue(previous.Name, out var match); + if (match is null) + { + declaredNames.TryGetValue(previous.Name, out match); + } + if (match is null) + { + normalizedNames.TryGetValue(NormalizeParameterName(previous.Name), out match); + } + if (match is null || !previous.Type.AreNamesEqual(match.Type) + || !match.Attributes.SequenceEqual(previous.Attributes) || !used.Add(match)) { return false; } + ordered[i] = match; } + matchedParameters = ordered; return true; + + static string NormalizeParameterName(string name) + => name.NormalizeCSharpAcronyms(useCamelCase: true).ToVariableName(); + + static void AddAlias(Dictionary aliases, string name, ParameterProvider parameter) + { + if (aliases.TryGetValue(name, out var existing) && !ReferenceEquals(existing, parameter)) + { + aliases[name] = null; + } + else + { + aliases[name] = parameter; + } + } } internal static bool HaveSameParametersInSameOrder(MethodSignature method1, MethodSignature method2) @@ -308,30 +360,5 @@ private static int GetMinimumArgumentCount(MethodSignature methodSignature) return count; } - - private sealed class ParameterProviderVariableNameComparer : IEqualityComparer - { - public bool Equals(ParameterProvider? x, ParameterProvider? y) - { - if (ReferenceEquals(x, y)) - { - return true; - } - - if (x is null || y is null) - { - return false; - } - - return x.Type.AreNamesEqual(y.Type) - && x.Name.ToVariableName() == y.Name.ToVariableName() - && x.Attributes.SequenceEqual(y.Attributes); - } - - public int GetHashCode(ParameterProvider obj) - { - return HashCode.Combine(obj.Name.ToVariableName()); - } - } } } diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Snippets/Snippet.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Snippets/Snippet.cs index daa2a953e45..5350ce1ccaa 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Snippets/Snippet.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Snippets/Snippet.cs @@ -28,7 +28,7 @@ public static partial class Snippet public static ValueExpression NullCoalesce(this ParameterProvider parameter, ValueExpression value) => new BinaryOperatorExpression("??", parameter, value); public static ValueExpression NullCoalesce(this FieldProvider field, ValueExpression value) => new BinaryOperatorExpression("??", field, value); public static ValueExpression PositionalReference(this ParameterProvider parameter, ValueExpression value) - => new PositionalParameterReferenceExpression(parameter.Name, value); + => new PositionalParameterReferenceExpression(parameter, value); public static ValueExpression PositionalReference(string parameterName, ValueExpression value) => new PositionalParameterReferenceExpression(parameterName, value); @@ -136,7 +136,7 @@ public static InvokeMethodExpression Invoke(this ParameterProvider parameter, st => new InvokeMethodExpression(parameter, methodName, args); public static InvokeMethodExpression Invoke(this ParameterProvider parameter, string methodName, CSharpType? extensionType = null) - => new InvokeMethodExpression(parameter, methodName, Array.Empty()) { ExtensionType = extensionType}; + => new InvokeMethodExpression(parameter, methodName, Array.Empty()) { ExtensionType = extensionType }; public static InvokeMethodExpression InvokeLambda(this ParameterProvider parameter, params ValueExpression[] args) => new InvokeMethodExpression(null, parameter.Name, args); diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Utilities/BackCompatHelper.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Utilities/BackCompatHelper.cs index a0feb39b122..7f019b58f65 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Utilities/BackCompatHelper.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Utilities/BackCompatHelper.cs @@ -92,7 +92,7 @@ public static bool IsConstructorRemovalAcceptedInBaseline(TypeProvider enclosing foreach (var kvp in currentMethodSignatures) { var currentSignature = kvp.Key; - if (currentSignature.Name.Equals(previousSignature.Name) + if (!kvp.Value.IsPartialMethod && currentSignature.Name.Equals(previousSignature.Name) && currentSignature.ReturnType?.AreNamesEqual(previousSignature.ReturnType) == true && MethodSignatureHelper.ContainsSameParameters(previousSignature, currentSignature)) { @@ -130,12 +130,15 @@ public static bool ParametersMatch(IReadOnlyList params1, IRe /// , looked up in . When /// is supplied, the search is scoped to last-contract methods /// whose name matches it (allowing for a sync/async pair) so a parameter name shared across - /// methods cannot cross-match. Returns null when no match exists. + /// methods cannot cross-match. When supplied, must also match. + /// Omit the type for name-only restoration, including existing date/time type changes. + /// Returns null when no match exists. /// public static string? FindPreviousParameterName( TypeProvider? lastContractView, string originalName, - string? methodName = null) + string? methodName = null, + CSharpType? parameterType = null) { var lastContractMethods = lastContractView?.Methods; if (lastContractMethods is null || lastContractMethods.Count == 0) @@ -154,7 +157,8 @@ public static bool ParametersMatch(IReadOnlyList params1, IRe return scopedMethods .SelectMany(method => method.Signature.Parameters) - .FirstOrDefault(p => string.Equals(p.Name, originalName, StringComparison.OrdinalIgnoreCase)) + .FirstOrDefault(p => string.Equals(p.Name, originalName, StringComparison.OrdinalIgnoreCase) + && (parameterType == null || p.Type.AreNamesEqual(parameterType))) ?.Name; } @@ -170,8 +174,16 @@ public static void RestorePreviousParameterNames( foreach (var method in currentMethods) { + // Custom partial declarations choose their names explicitly and take precedence over the last contract. + if (method.IsPartialMethod) + { + continue; + } + var modifiers = method.Signature.Modifiers; - if (!modifiers.HasFlag(MethodSignatureModifiers.Public) && !modifiers.HasFlag(MethodSignatureModifiers.Protected)) + var isPublicOrProtected = modifiers.HasFlag(MethodSignatureModifiers.Public) + || modifiers.HasFlag(MethodSignatureModifiers.Protected); + if (!isPublicOrProtected) { continue; } @@ -198,7 +210,21 @@ public static void RestorePreviousParameterNames( var inputParameter = parameter.InputParameter; if (inputParameter is not null && !parameter.IsContentParameter) { - preservedName = FindPreviousParameterName(lastContractView, inputParameter.OriginalName, method.Signature.Name); + if (matchingPrevious != null) + { + preservedName = matchingPrevious.Signature.Parameters.FirstOrDefault(p => + string.Equals(p.Name, inputParameter.OriginalName, StringComparison.OrdinalIgnoreCase))?.Name; + } + else + { + // Date/time inputs keep the legacy fallback even when their names also contain acronyms. + var hasAcronymRename = inputParameter.Name != inputParameter.Name.NormalizeCSharpAcronyms(useCamelCase: true); + if (!hasAcronymRename || inputParameter.Type.IsDateTimeInputType()) + { + preservedName = FindPreviousParameterName( + lastContractView, inputParameter.OriginalName, method.Signature.Name); + } + } } // Fall back to a positional match for synthesized parameters @@ -275,31 +301,31 @@ public static bool TryRestorePreviousParameterOrder( MethodSignature previousSignature) { var currentSignature = methodToReorder.Signature; - if (MethodSignatureHelper.HaveSameParametersInSameOrder(currentSignature, previousSignature)) + if (methodToReorder.IsPartialMethod + || !MethodSignatureHelper.TryMatchParameterOrder(currentSignature.Parameters, previousSignature.Parameters, out var reorderedParameters)) { return false; } - var parametersByName = currentSignature.Parameters.ToDictionary(p => p.Name.ToVariableName()); - var reorderedParameters = new List(currentSignature.Parameters.Count); - - foreach (var previousParam in previousSignature.Parameters) + bool orderChanged = false; + for (int i = 0; i < reorderedParameters.Length; i++) { - if (parametersByName.TryGetValue(previousParam.Name.ToVariableName(), out var matchingParam)) + if (!ReferenceEquals(currentSignature.Parameters[i], reorderedParameters[i])) { - reorderedParameters.Add(matchingParam); + orderChanged = true; + break; } } - - if (reorderedParameters.Count != currentSignature.Parameters.Count) + if (!orderChanged) { return false; } - foreach (var previousParam in previousSignature.Parameters) + for (int i = 0; i < reorderedParameters.Length; i++) { - if (parametersByName.TryGetValue(previousParam.Name.ToVariableName(), out var matchingParam) - && matchingParam.DefaultValue is not null + var matchingParam = reorderedParameters[i]; + var previousParam = previousSignature.Parameters[i]; + if (matchingParam.DefaultValue is not null && previousParam.DefaultValue is not null) { matchingParam.Update(defaultValue: previousParam.DefaultValue); diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Expressions/PositionalParameterReferenceExpressionTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Expressions/PositionalParameterReferenceExpressionTests.cs index 7c480689cdb..6d41e9bc0ae 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Expressions/PositionalParameterReferenceExpressionTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Expressions/PositionalParameterReferenceExpressionTests.cs @@ -3,12 +3,30 @@ using Microsoft.TypeSpec.Generator.Expressions; using Microsoft.TypeSpec.Generator.Input.Extensions; +using Microsoft.TypeSpec.Generator.Providers; +using Microsoft.TypeSpec.Generator.Snippets; using NUnit.Framework; namespace Microsoft.TypeSpec.Generator.Tests.Expressions { public class PositionalParameterReferenceExpressionTests { + [TestCase("sourceIpAddress")] + [TestCase("iPv4Address")] + [TestCase("object")] + public void NamedArgumentTracksRestoredParameterName(string restoredName) + { + var parameter = new ParameterProvider("sourceIPAddress", $"", typeof(string)); + var expression = parameter.PositionalReference(Snippet.Null); + parameter.Update(name: restoredName); + Assert.AreEqual(restoredName, ((PositionalParameterReferenceExpression)expression).ParameterName); + + using CodeWriter writer = new CodeWriter(); + expression.Write(writer); + + Assert.AreEqual($"{(restoredName == "object" ? "@object" : restoredName)}: null", writer.ToString(false)); + } + [Test] public void NonKeywordParameterName() { 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 2a7f2b006c2..a49bdde6e6d 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 @@ -98,6 +98,134 @@ public void VariableNamePreservesExistingCamelCase(string name, string expected) Assert.AreEqual(expected, parameter.AsVariable().Declaration.RequestedName); } + [TestCase("sourceIpAddress", "sourceIPAddress")] + [TestCase("targetDbName", "targetDBName")] + [TestCase("guestOsType", "guestOSType")] + [TestCase("ipAddress", "ipAddress")] + [TestCase("dbName", "dbName")] + [TestCase("osType", "osType")] + [TestCase("ipv4Address", "ipv4Address")] + [TestCase("ipv6Address", "ipv6Address")] + [TestCase("ipV4Address", "ipv4Address")] + [TestCase("ipV6Address", "ipv6Address")] + [TestCase("iPv4Address", "ipv4Address")] + [TestCase("iPv6Address", "ipv6Address")] + [TestCase("sourceIpv4Address", "sourceIPv4Address")] + [TestCase("sourceIpV6Address", "sourceIPv6Address")] + [TestCase("sourceIpIpDbOs", "sourceIPIPDBOS")] // cspell:ignore IPIPDBOS + [TestCase("sourceIPv4Address", "sourceIPv4Address")] + [TestCase("sourceIPAddress", "sourceIPAddress")] + [TestCase("targetDBName", "targetDBName")] + [TestCase("guestOSType", "guestOSType")] + [TestCase("sourceIpad", "sourceIpad")] + [TestCase("targetDbase", "targetDbase")] // cspell:ignore Dbase + [TestCase("guestOstrich", "guestOstrich")] + [TestCase("sourceIpv4address", "sourceIpv4address")] + [TestCase("sourceIp2Address", "sourceIp2Address")] + public void MethodParameterNameNormalizesAcronyms(string name, string expected) + { + MockHelpers.LoadMockGenerator(); + var input = InputFactory.MethodParameter(name, InputPrimitiveType.String, isRequired: true); + var parameter = CodeModelGenerator.Instance.TypeFactory.CreateParameter(input)!; + + Assert.AreEqual(expected, parameter.Name); + Assert.AreEqual(expected, parameter.AsVariable().Declaration.RequestedName); + Assert.AreEqual(expected, parameter.ToPublicInputParameter().Name); + Assert.AreEqual(name, parameter.WireInfo.SerializedName); + Assert.AreEqual(name, input.Name); + } + + [TestCase("sourceIpAddress")] + [TestCase("targetDbName")] + [TestCase("guestOsType")] + [TestCase("iPv4Address")] + [TestCase("iPv6Address")] + public void ExactMethodParameterNameDoesNotNormalizeAcronyms(string name) + { + MockHelpers.LoadMockGenerator(); + var input = InputFactory.MethodParameter(name, InputPrimitiveType.String, isExactName: true); + var parameter = CodeModelGenerator.Instance.TypeFactory.CreateParameter(input)!; + + Assert.AreEqual(name, parameter.Name); + Assert.AreEqual(name, parameter.AsVariable().Declaration.RequestedName); + Assert.AreEqual(name, parameter.ToPublicInputParameter().Name); + } + + [Test] + public void ClientParameterNamePreservesAcronyms( + [Values("sourceIpAddress", "targetDbName", "guestOsType", "iPv4Address")] string name, + [Values(false, true)] bool isExactName) + { + MockHelpers.LoadMockGenerator(); + var input = InputFactory.MethodParameter( + name, InputPrimitiveType.String, isRequired: true, scope: InputParameterScope.Client, isExactName: isExactName); + var parameter = CodeModelGenerator.Instance.TypeFactory.CreateParameter(input)!; + + Assert.AreEqual(name, parameter.Name); + Assert.AreEqual(name, parameter.AsVariable().Declaration.RequestedName); + Assert.AreEqual(name, parameter.ToPublicInputParameter().Name); + Assert.AreEqual(name, parameter.WireInfo.SerializedName); + } + + [TestCase("startTime", "startsOn")] + [TestCase("sourceIpCreationTime", "sourceIpCreatedOn")] + public void ClientParameterNameRetainsDateTimeNormalization(string name, string expected) + { + MockHelpers.LoadMockGenerator(); + var dateTime = new InputDateTimeType( + DateTimeKnownEncoding.Rfc3339, "utcDateTime", "TypeSpec.utcDateTime", InputPrimitiveType.String); + var input = InputFactory.MethodParameter(name, dateTime, isRequired: true, scope: InputParameterScope.Client); + var parameter = CodeModelGenerator.Instance.TypeFactory.CreateParameter(input)!; + + Assert.AreEqual(expected, parameter.Name); + Assert.AreEqual(expected, parameter.AsVariable().Declaration.RequestedName); + Assert.AreEqual(name, parameter.WireInfo.SerializedName); + } + + [Test] + public void IndependentlyCreatedParametersPreserveMetadata() + { + MockHelpers.LoadMockGenerator(); + var input = InputFactory.MethodParameter("iPv4Address", InputPrimitiveType.String, isExactName: true); + var parameter = CodeModelGenerator.Instance.TypeFactory.CreateParameter(input)!; + var variable = parameter.AsVariable(); + var independentParameter = CodeModelGenerator.Instance.TypeFactory.CreateParameter(input)!; + + Assert.AreEqual(parameter, independentParameter); + Assert.AreSame(input, independentParameter.InputParameter); + Assert.AreEqual(parameter.WireInfo.SerializedName, independentParameter.WireInfo.SerializedName); + Assert.AreEqual(parameter.IsExactName, independentParameter.IsExactName); + Assert.AreEqual(parameter.DefaultValue, independentParameter.DefaultValue); + Assert.AreEqual(parameter.Validation, independentParameter.Validation); + Assert.AreNotSame(variable, independentParameter.AsVariable()); + + independentParameter.Update(name: "publishedIPv4Address"); + Assert.AreEqual("publishedIPv4Address", independentParameter.AsVariable().Declaration.RequestedName); + Assert.AreEqual("iPv4Address", parameter.Name); + Assert.AreEqual("iPv4Address", variable.Declaration.RequestedName); + } + + [Test] + public void PublicInputVariantPreservesVariableAndMetadata() + { + MockHelpers.LoadMockGenerator(); + var input = InputFactory.MethodParameter( + "iPv4Addresses", InputFactory.Array(InputPrimitiveType.String), isExactName: true); + var parameter = CodeModelGenerator.Instance.TypeFactory.CreateParameter(input)!; + var variable = parameter.AsVariable(); + var inputVariant = parameter.ToPublicInputParameter(); + + Assert.AreEqual(parameter.Name, inputVariant.Name); + Assert.IsTrue(inputVariant.Type.Equals(typeof(IEnumerable))); + Assert.AreSame(variable, inputVariant.AsVariable()); + Assert.AreSame(input, inputVariant.InputParameter); + Assert.AreSame(parameter.WireInfo, inputVariant.WireInfo); + Assert.AreEqual(parameter.IsExactName, inputVariant.IsExactName); + Assert.AreEqual(parameter.DefaultValue, inputVariant.DefaultValue); + Assert.AreEqual(parameter.Validation, inputVariant.Validation); + Assert.AreSame(inputVariant, parameter.ToPublicInputParameter()); + } + private static IEnumerable ValueInputTypes() { yield return InputPrimitiveType.Int32; @@ -116,6 +244,8 @@ private static IEnumerable DateTimeParameterNameTestCases() var testCases = new (string Name, InputType Type, string NormalizedName)[] { ("startTime", dateTime, "startsOn"), + ("sourceIpCreationTime", dateTime, "sourceIPCreatedOn"), + ("ipStartTime", dateTime, "ipStartsOn"), ("endTime", dateTime, "endsOn"), ("startOn", dateTime, "startsOn"), ("endOn", dateTime, "endsOn"), diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/TestData/TypeProviderTests/MixedAcronymDateTimeRenameRetainsLegacyFallback/TestClient.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/TestData/TypeProviderTests/MixedAcronymDateTimeRenameRetainsLegacyFallback/TestClient.cs new file mode 100644 index 00000000000..79f2d8f733d --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/TestData/TypeProviderTests/MixedAcronymDateTimeRenameRetainsLegacyFallback/TestClient.cs @@ -0,0 +1,10 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace Test +{ + public class TestClient + { + public string Foo(string sourceIpCreationTime) => default; + } +} diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/TypeProviderTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/TypeProviderTests.cs index 05fae1279ce..643b6c2265d 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/TypeProviderTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/TypeProviderTests.cs @@ -1005,6 +1005,9 @@ public async Task FindPreviousParameterNameLooksUpLastContract() // The last contract published Foo(string oldParam); scoped to that method it is found. Assert.AreEqual("oldParam", BackCompatHelper.FindPreviousParameterName(lastContractView, "oldParam", "Foo")); + Assert.AreEqual("oldParam", BackCompatHelper.FindPreviousParameterName(lastContractView, "oldParam", "Foo", typeof(string))); + Assert.IsNull(BackCompatHelper.FindPreviousParameterName(lastContractView, "oldParam", "Foo", typeof(int))); + // The exact casing from the contract is returned even when the lookup name differs only in casing. Assert.AreEqual("oldParam", BackCompatHelper.FindPreviousParameterName(lastContractView, "oldparam", "Foo")); @@ -1030,6 +1033,122 @@ public void FindPreviousParameterNameReturnsNullWithoutLastContract() Assert.IsNull(BackCompatHelper.FindPreviousParameterName(typeProvider.LastContractView, "oldParam", "Foo")); } + [Test] + public void AcronymParameterReorderingPreservesPublishedDefaults() + { + MockHelpers.LoadMockGenerator(); + var source = new ParameterProvider(InputFactory.MethodParameter("sourceIpAddress", InputPrimitiveType.String)); + var target = new ParameterProvider(InputFactory.MethodParameter("targetDbName", InputPrimitiveType.String)); + var sourceDefault = Snippet.Literal("source"); + var targetDefault = Snippet.Literal("target"); + var method = new MethodProvider( + new MethodSignature("Foo", $"", MethodSignatureModifiers.Public, typeof(string), $"", [source, target]), + Snippet.Return(Snippet.Null), new TestTypeProvider()); + var previous = new MethodSignature( + "Foo", $"", MethodSignatureModifiers.Public, typeof(string), $"", + [new ParameterProvider("targetDbName", $"", target.Type, targetDefault), new ParameterProvider("sourceIpAddress", $"", source.Type, sourceDefault)]); + + Assert.IsTrue(BackCompatHelper.TryRestorePreviousParameterOrder(method, previous)); + Assert.AreSame(target, method.Signature.Parameters[0]); + Assert.AreSame(source, method.Signature.Parameters[1]); + Assert.AreSame(targetDefault, target.DefaultValue); + Assert.AreSame(sourceDefault, source.DefaultValue); + } + + [Test] + public void ParameterOrderUsesRawIdentityWhenNormalizedNamesCollide() + { + MockHelpers.LoadMockGenerator(); + var dateTime = new InputDateTimeType( + DateTimeKnownEncoding.Rfc3339, "utcDateTime", "TypeSpec.utcDateTime", InputPrimitiveType.String); + var first = new ParameterProvider(InputFactory.MethodParameter("startTime", dateTime, isRequired: true)); + var second = new ParameterProvider(InputFactory.MethodParameter("startsOn", dateTime, isRequired: true)); + ParameterProvider[] previous = + [new ParameterProvider("startsOn", $"", first.Type), new ParameterProvider("startTime", $"", first.Type)]; + + Assert.IsTrue(MethodSignatureHelper.TryMatchParameterOrder([first, second], previous, out var matched)); + Assert.AreSame(second, matched[0]); + Assert.AreSame(first, matched[1]); + } + + [Test] + public void ParameterOrderPreservesExactCaseSensitiveIdentities() + { + MockHelpers.LoadMockGenerator(); + var first = new ParameterProvider(InputFactory.MethodParameter("sourceIPAddress", InputPrimitiveType.String, isRequired: true, isExactName: true)); + var second = new ParameterProvider(InputFactory.MethodParameter("sourceIpAddress", InputPrimitiveType.String, isRequired: true, isExactName: true)); + var method = new MethodProvider( + new MethodSignature("Foo", $"", MethodSignatureModifiers.Public, typeof(string), $"", [first, second]), + Snippet.Return(Snippet.Null), new TestTypeProvider()); + var previous = new MethodSignature( + "Foo", $"", MethodSignatureModifiers.Public, typeof(string), $"", + [new ParameterProvider("sourceIpAddress", $"", typeof(string)), new ParameterProvider("sourceIPAddress", $"", typeof(string))]); + + Assert.IsTrue(BackCompatHelper.TryRestorePreviousParameterOrder(method, previous)); + Assert.AreSame(second, method.Signature.Parameters[0]); + Assert.AreSame(first, method.Signature.Parameters[1]); + Assert.AreEqual("sourceIPAddress", first.Name); + Assert.AreEqual("sourceIpAddress", second.Name); + } + + [Test] + public void ParameterOrderRejectsAmbiguousNormalizedIdentities() + { + MockHelpers.LoadMockGenerator(); + var first = new ParameterProvider("sourceIpAddress", $"", typeof(string)); + var second = new ParameterProvider("sourceIPAddress", $"", typeof(string)); + var method = new MethodProvider( + new MethodSignature("Foo", $"", MethodSignatureModifiers.Public, typeof(string), $"", [first, second]), + Snippet.Return(Snippet.Null), new TestTypeProvider()); + var previous = new MethodSignature( + "Foo", $"", MethodSignatureModifiers.Public, typeof(string), $"", + [new ParameterProvider("SOURCEIPADDRESS", $"", typeof(string)), new ParameterProvider("other", $"", typeof(string))]); + + Assert.IsFalse(BackCompatHelper.TryRestorePreviousParameterOrder(method, previous)); + Assert.AreSame(first, method.Signature.Parameters[0]); + Assert.AreSame(second, method.Signature.Parameters[1]); + } + + [Test] + public void PublishedParameterOrderDoesNotOverridePartialDeclarations() + { + MockHelpers.LoadMockGenerator(); + var source = new ParameterProvider(InputFactory.MethodParameter("sourceIpAddress", InputPrimitiveType.String, isRequired: true)); + var target = new ParameterProvider(InputFactory.MethodParameter("targetDbName", InputPrimitiveType.Int32, isRequired: true)); + var method = new MethodProvider( + new MethodSignature("Foo", $"", MethodSignatureModifiers.Public | MethodSignatureModifiers.Partial, typeof(string), $"", [source, target]), + Snippet.Return(Snippet.Null), new TestTypeProvider()); + var previous = new MethodSignature( + "Foo", $"", MethodSignatureModifiers.Public, typeof(string), $"", + [new ParameterProvider("targetDbName", $"", typeof(int)), new ParameterProvider("sourceIpAddress", $"", typeof(string))]); + + Assert.IsFalse(BackCompatHelper.TryRestorePreviousParameterOrder(method, previous)); + Assert.IsNull(BackCompatHelper.FindMethodWithSameParametersDifferentOrder(previous, + new Dictionary { [method.Signature] = method })); + Assert.AreSame(source, method.Signature.Parameters[0]); + Assert.AreSame(target, method.Signature.Parameters[1]); + } + + [Test] + public async Task MixedAcronymDateTimeRenameRetainsLegacyFallback() + { + await MockHelpers.LoadMockGeneratorAsync(lastContractCompilation: async () => await Helpers.GetCompilationFromDirectoryAsync()); + var dateTime = new InputDateTimeType( + DateTimeKnownEncoding.Rfc3339, "utcDateTime", "TypeSpec.utcDateTime", InputPrimitiveType.String); + var parameter = new ParameterProvider(InputFactory.MethodParameter("sourceIpCreationTime", dateTime, isRequired: true)); + Assert.AreEqual("sourceIPCreatedOn", parameter.Name); + var method = new MethodProvider( + new MethodSignature("Foo", $"", MethodSignatureModifiers.Public, typeof(string), $"", [parameter]), + Snippet.Return(Snippet.Null), + new TestTypeProvider()); + var type = new TestTypeProvider(name: "TestClient", methods: [method]); + + BackCompatHelper.RestorePreviousParameterNames(type, type.Methods); + + Assert.AreEqual("sourceIpCreationTime", parameter.Name); + Assert.AreEqual("sourceIpCreationTime", parameter.AsVariable().Declaration.RequestedName); + } + [Test] public async Task RestorePreviousParameterNamesRestoresNormalizedMethodParameterName() { diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/Sample-TypeSpec.tsp b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/Sample-TypeSpec.tsp index b098bdd5798..f62a36fe198 100644 --- a/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/Sample-TypeSpec.tsp +++ b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/Sample-TypeSpec.tsp @@ -676,6 +676,22 @@ op sayHi( @query optionalQuery?: string, ): Thing; +@route("/acronyms/{targetDbName}") +@doc("Send acronym-named path, query, and header parameters.") +@get +@convenientAPI(true, "csharp") +op getAcronymParameters( + @path targetDbName: string, + @query sourceIpAddress?: string, + @header("X-Guest-OS-Type") guestOsType?: string, +): void; + +@route("/acronyms/addresses") +@doc("Send parameters with leading IP version acronyms.") +@post +@convenientAPI(true, "csharp") +op setAcronymAddresses(@query ipV4Address: string, @query ipV6Address?: string): void; + @route("/againHi") @doc("Return hi again") @get diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/SampleTypeSpecClient.RestClient.cs b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/SampleTypeSpecClient.RestClient.cs index 167d7ee9448..d9d35df15a3 100644 --- a/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/SampleTypeSpecClient.RestClient.cs +++ b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/SampleTypeSpecClient.RestClient.cs @@ -39,6 +39,42 @@ internal PipelineMessage CreateSayHiRequest(string headParameter, string queryPa return message; } + internal PipelineMessage CreateGetAcronymParametersRequest(string targetDBName, string sourceIPAddress, string guestOSType, RequestOptions options) + { + ClientUriBuilder uri = new ClientUriBuilder(); + uri.Reset(_endpoint); + uri.AppendPath("/acronyms/", false); + uri.AppendPath(targetDBName, true); + if (sourceIPAddress != null) + { + uri.AppendQuery("sourceIpAddress", sourceIPAddress, true); + } + PipelineMessage message = Pipeline.CreateMessage(uri.ToUri(), "GET", PipelineMessageClassifier204); + PipelineRequest request = message.Request; + if (guestOSType != null) + { + request.Headers.Set("X-Guest-OS-Type", guestOSType); + } + message.Apply(options); + return message; + } + + internal PipelineMessage CreateSetAcronymAddressesRequest(string ipv4Address, string ipv6Address, RequestOptions options) + { + ClientUriBuilder uri = new ClientUriBuilder(); + uri.Reset(_endpoint); + uri.AppendPath("/acronyms/addresses", false); + uri.AppendQuery("ipV4Address", ipv4Address, true); + if (ipv6Address != null) + { + uri.AppendQuery("ipV6Address", ipv6Address, true); + } + PipelineMessage message = Pipeline.CreateMessage(uri.ToUri(), "POST", PipelineMessageClassifier204); + PipelineRequest request = message.Request; + message.Apply(options); + return message; + } + internal PipelineMessage CreateHelloAgainRequest(string p2, string p1, BinaryContent content, RequestOptions options) { ClientUriBuilder uri = new ClientUriBuilder(); diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/SampleTypeSpecClient.cs b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/SampleTypeSpecClient.cs index ef008649fd5..ec57dc96aad 100644 --- a/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/SampleTypeSpecClient.cs +++ b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/SampleTypeSpecClient.cs @@ -189,6 +189,158 @@ public virtual async Task> SayHiAsync(string headParameter, return ClientResult.FromValue((Thing)result, result.GetRawResponse()); } + /// + /// [Protocol Method] Send acronym-named path, query, and header parameters. + /// + /// + /// This protocol method allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// + /// + /// + /// + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// is null. + /// is an empty string, and was expected to be non-empty. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual ClientResult GetAcronymParameters(string targetDBName, string sourceIPAddress, string guestOSType, RequestOptions options) + { + Argument.AssertNotNullOrEmpty(targetDBName, nameof(targetDBName)); + + using PipelineMessage message = CreateGetAcronymParametersRequest(targetDBName, sourceIPAddress, guestOSType, options); + return ClientResult.FromResponse(Pipeline.ProcessMessage(message, options)); + } + + /// + /// [Protocol Method] Send acronym-named path, query, and header parameters. + /// + /// + /// This protocol method allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// + /// + /// + /// + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// is null. + /// is an empty string, and was expected to be non-empty. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual async Task GetAcronymParametersAsync(string targetDBName, string sourceIPAddress, string guestOSType, RequestOptions options) + { + Argument.AssertNotNullOrEmpty(targetDBName, nameof(targetDBName)); + + using PipelineMessage message = CreateGetAcronymParametersRequest(targetDBName, sourceIPAddress, guestOSType, options); + return ClientResult.FromResponse(await Pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); + } + + /// Send acronym-named path, query, and header parameters. + /// + /// + /// + /// The cancellation token that can be used to cancel the operation. + /// is null. + /// is an empty string, and was expected to be non-empty. + /// Service returned a non-success status code. + public virtual ClientResult GetAcronymParameters(string targetDBName, string sourceIPAddress = default, string guestOSType = default, CancellationToken cancellationToken = default) + { + Argument.AssertNotNullOrEmpty(targetDBName, nameof(targetDBName)); + + return GetAcronymParameters(targetDBName, sourceIPAddress, guestOSType, cancellationToken.ToRequestOptions()); + } + + /// Send acronym-named path, query, and header parameters. + /// + /// + /// + /// The cancellation token that can be used to cancel the operation. + /// is null. + /// is an empty string, and was expected to be non-empty. + /// Service returned a non-success status code. + public virtual async Task GetAcronymParametersAsync(string targetDBName, string sourceIPAddress = default, string guestOSType = default, CancellationToken cancellationToken = default) + { + Argument.AssertNotNullOrEmpty(targetDBName, nameof(targetDBName)); + + return await GetAcronymParametersAsync(targetDBName, sourceIPAddress, guestOSType, cancellationToken.ToRequestOptions()).ConfigureAwait(false); + } + + /// + /// [Protocol Method] Send parameters with leading IP version acronyms. + /// + /// + /// This protocol method allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// + /// + /// + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// is null. + /// is an empty string, and was expected to be non-empty. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual ClientResult SetAcronymAddresses(string ipv4Address, string ipv6Address, RequestOptions options) + { + Argument.AssertNotNullOrEmpty(ipv4Address, nameof(ipv4Address)); + + using PipelineMessage message = CreateSetAcronymAddressesRequest(ipv4Address, ipv6Address, options); + return ClientResult.FromResponse(Pipeline.ProcessMessage(message, options)); + } + + /// + /// [Protocol Method] Send parameters with leading IP version acronyms. + /// + /// + /// This protocol method allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// + /// + /// + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// is null. + /// is an empty string, and was expected to be non-empty. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual async Task SetAcronymAddressesAsync(string ipv4Address, string ipv6Address, RequestOptions options) + { + Argument.AssertNotNullOrEmpty(ipv4Address, nameof(ipv4Address)); + + using PipelineMessage message = CreateSetAcronymAddressesRequest(ipv4Address, ipv6Address, options); + return ClientResult.FromResponse(await Pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); + } + + /// Send parameters with leading IP version acronyms. + /// + /// + /// The cancellation token that can be used to cancel the operation. + /// is null. + /// is an empty string, and was expected to be non-empty. + /// Service returned a non-success status code. + public virtual ClientResult SetAcronymAddresses(string ipv4Address, string ipv6Address = default, CancellationToken cancellationToken = default) + { + Argument.AssertNotNullOrEmpty(ipv4Address, nameof(ipv4Address)); + + return SetAcronymAddresses(ipv4Address, ipv6Address, cancellationToken.ToRequestOptions()); + } + + /// Send parameters with leading IP version acronyms. + /// + /// + /// The cancellation token that can be used to cancel the operation. + /// is null. + /// is an empty string, and was expected to be non-empty. + /// Service returned a non-success status code. + public virtual async Task SetAcronymAddressesAsync(string ipv4Address, string ipv6Address = default, CancellationToken cancellationToken = default) + { + Argument.AssertNotNullOrEmpty(ipv4Address, nameof(ipv4Address)); + + return await SetAcronymAddressesAsync(ipv4Address, ipv6Address, cancellationToken.ToRequestOptions()).ConfigureAwait(false); + } + /// /// [Protocol Method] Return hi again /// diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/tspCodeModel.json b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/tspCodeModel.json index 85d76225719..59ac62c1458 100644 --- a/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/tspCodeModel.json +++ b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/tspCodeModel.json @@ -11055,6 +11055,345 @@ { "$id": "777", "kind": "basic", + "name": "getAcronymParameters", + "isExactName": false, + "accessibility": "public", + "apiVersions": [ + "2024-07-16-preview", + "2024-08-16-preview" + ], + "doc": "Send acronym-named path, query, and header parameters.", + "operation": { + "$id": "778", + "name": "getAcronymParameters", + "isExactName": false, + "resourceName": "SampleTypeSpec", + "doc": "Send acronym-named path, query, and header parameters.", + "accessibility": "public", + "parameters": [ + { + "$id": "779", + "kind": "path", + "name": "targetDbName", + "serializedName": "targetDbName", + "type": { + "$id": "780", + "kind": "string", + "name": "string", + "crossLanguageDefinitionId": "TypeSpec.string", + "decorators": [] + }, + "isApiVersion": false, + "explode": false, + "style": "simple", + "allowReserved": false, + "skipUrlEncoding": false, + "optional": false, + "scope": "Method", + "decorators": [], + "readOnly": false, + "crossLanguageDefinitionId": "SampleTypeSpec.getAcronymParameters.targetDbName", + "methodParameterSegments": [ + { + "$id": "781", + "kind": "method", + "name": "targetDbName", + "serializedName": "targetDbName", + "type": { + "$id": "782", + "kind": "string", + "name": "string", + "crossLanguageDefinitionId": "TypeSpec.string", + "decorators": [] + }, + "location": "Path", + "isApiVersion": false, + "optional": false, + "scope": "Method", + "crossLanguageDefinitionId": "SampleTypeSpec.getAcronymParameters.targetDbName", + "readOnly": false, + "access": "public", + "decorators": [], + "isExactName": false + } + ], + "isExactName": false + }, + { + "$id": "783", + "kind": "query", + "name": "sourceIpAddress", + "serializedName": "sourceIpAddress", + "type": { + "$id": "784", + "kind": "string", + "name": "string", + "crossLanguageDefinitionId": "TypeSpec.string", + "decorators": [] + }, + "isApiVersion": false, + "explode": false, + "optional": true, + "scope": "Method", + "decorators": [], + "crossLanguageDefinitionId": "SampleTypeSpec.getAcronymParameters.sourceIpAddress", + "readOnly": false, + "methodParameterSegments": [ + { + "$id": "785", + "kind": "method", + "name": "sourceIpAddress", + "serializedName": "sourceIpAddress", + "type": { + "$id": "786", + "kind": "string", + "name": "string", + "crossLanguageDefinitionId": "TypeSpec.string", + "decorators": [] + }, + "location": "Query", + "isApiVersion": false, + "optional": true, + "scope": "Method", + "crossLanguageDefinitionId": "SampleTypeSpec.getAcronymParameters.sourceIpAddress", + "readOnly": false, + "access": "public", + "decorators": [], + "isExactName": false + } + ], + "isExactName": false + }, + { + "$id": "787", + "kind": "header", + "name": "guestOsType", + "serializedName": "X-Guest-OS-Type", + "type": { + "$id": "788", + "kind": "string", + "name": "string", + "crossLanguageDefinitionId": "TypeSpec.string", + "decorators": [] + }, + "isApiVersion": false, + "optional": true, + "isContentType": false, + "scope": "Method", + "readOnly": false, + "decorators": [], + "crossLanguageDefinitionId": "SampleTypeSpec.getAcronymParameters.guestOsType", + "methodParameterSegments": [ + { + "$id": "789", + "kind": "method", + "name": "guestOsType", + "serializedName": "X-Guest-OS-Type", + "type": { + "$id": "790", + "kind": "string", + "name": "string", + "crossLanguageDefinitionId": "TypeSpec.string", + "decorators": [] + }, + "location": "Header", + "isApiVersion": false, + "optional": true, + "scope": "Method", + "crossLanguageDefinitionId": "SampleTypeSpec.getAcronymParameters.guestOsType", + "readOnly": false, + "access": "public", + "decorators": [], + "isExactName": false + } + ], + "isExactName": false + } + ], + "responses": [ + { + "statusCodes": [ + 204 + ], + "headers": [], + "isErrorResponse": false, + "serializationOptions": {} + } + ], + "httpMethod": "GET", + "uri": "{sampleTypeSpecUrl}", + "path": "/acronyms/{targetDbName}", + "bufferResponse": true, + "generateProtocolMethod": true, + "generateConvenienceMethod": true, + "crossLanguageDefinitionId": "SampleTypeSpec.getAcronymParameters", + "decorators": [], + "namespace": "SampleTypeSpec" + }, + "parameters": [ + { + "$ref": "781" + }, + { + "$ref": "785" + }, + { + "$ref": "789" + } + ], + "response": {}, + "isOverride": false, + "generateConvenient": true, + "generateProtocol": true, + "crossLanguageDefinitionId": "SampleTypeSpec.getAcronymParameters" + }, + { + "$id": "791", + "kind": "basic", + "name": "setAcronymAddresses", + "isExactName": false, + "accessibility": "public", + "apiVersions": [ + "2024-07-16-preview", + "2024-08-16-preview" + ], + "doc": "Send parameters with leading IP version acronyms.", + "operation": { + "$id": "792", + "name": "setAcronymAddresses", + "isExactName": false, + "resourceName": "SampleTypeSpec", + "doc": "Send parameters with leading IP version acronyms.", + "accessibility": "public", + "parameters": [ + { + "$id": "793", + "kind": "query", + "name": "ipV4Address", + "serializedName": "ipV4Address", + "type": { + "$id": "794", + "kind": "string", + "name": "string", + "crossLanguageDefinitionId": "TypeSpec.string", + "decorators": [] + }, + "isApiVersion": false, + "explode": false, + "optional": false, + "scope": "Method", + "decorators": [], + "crossLanguageDefinitionId": "SampleTypeSpec.setAcronymAddresses.ipV4Address", + "readOnly": false, + "methodParameterSegments": [ + { + "$id": "795", + "kind": "method", + "name": "ipV4Address", + "serializedName": "ipV4Address", + "type": { + "$id": "796", + "kind": "string", + "name": "string", + "crossLanguageDefinitionId": "TypeSpec.string", + "decorators": [] + }, + "location": "Query", + "isApiVersion": false, + "optional": false, + "scope": "Method", + "crossLanguageDefinitionId": "SampleTypeSpec.setAcronymAddresses.ipV4Address", + "readOnly": false, + "access": "public", + "decorators": [], + "isExactName": false + } + ], + "isExactName": false + }, + { + "$id": "797", + "kind": "query", + "name": "ipV6Address", + "serializedName": "ipV6Address", + "type": { + "$id": "798", + "kind": "string", + "name": "string", + "crossLanguageDefinitionId": "TypeSpec.string", + "decorators": [] + }, + "isApiVersion": false, + "explode": false, + "optional": true, + "scope": "Method", + "decorators": [], + "crossLanguageDefinitionId": "SampleTypeSpec.setAcronymAddresses.ipV6Address", + "readOnly": false, + "methodParameterSegments": [ + { + "$id": "799", + "kind": "method", + "name": "ipV6Address", + "serializedName": "ipV6Address", + "type": { + "$id": "800", + "kind": "string", + "name": "string", + "crossLanguageDefinitionId": "TypeSpec.string", + "decorators": [] + }, + "location": "Query", + "isApiVersion": false, + "optional": true, + "scope": "Method", + "crossLanguageDefinitionId": "SampleTypeSpec.setAcronymAddresses.ipV6Address", + "readOnly": false, + "access": "public", + "decorators": [], + "isExactName": false + } + ], + "isExactName": false + } + ], + "responses": [ + { + "statusCodes": [ + 204 + ], + "headers": [], + "isErrorResponse": false, + "serializationOptions": {} + } + ], + "httpMethod": "POST", + "uri": "{sampleTypeSpecUrl}", + "path": "/acronyms/addresses", + "bufferResponse": true, + "generateProtocolMethod": true, + "generateConvenienceMethod": true, + "crossLanguageDefinitionId": "SampleTypeSpec.setAcronymAddresses", + "decorators": [], + "namespace": "SampleTypeSpec" + }, + "parameters": [ + { + "$ref": "795" + }, + { + "$ref": "799" + } + ], + "response": {}, + "isOverride": false, + "generateConvenient": true, + "generateProtocol": true, + "crossLanguageDefinitionId": "SampleTypeSpec.setAcronymAddresses" + }, + { + "$id": "801", + "kind": "basic", "name": "helloAgain", "isExactName": false, "accessibility": "public", @@ -11064,7 +11403,7 @@ ], "doc": "Return hi again", "operation": { - "$id": "778", + "$id": "802", "name": "helloAgain", "isExactName": false, "resourceName": "SampleTypeSpec", @@ -11072,12 +11411,12 @@ "accessibility": "public", "parameters": [ { - "$id": "779", + "$id": "803", "kind": "header", "name": "p1", "serializedName": "p1", "type": { - "$id": "780", + "$id": "804", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -11092,12 +11431,12 @@ "crossLanguageDefinitionId": "SampleTypeSpec.helloAgain.p1", "methodParameterSegments": [ { - "$id": "781", + "$id": "805", "kind": "method", "name": "p1", "serializedName": "p1", "type": { - "$id": "782", + "$id": "806", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -11117,7 +11456,7 @@ "isExactName": false }, { - "$id": "783", + "$id": "807", "kind": "header", "name": "contentType", "serializedName": "Content-Type", @@ -11133,7 +11472,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.helloAgain.contentType", "methodParameterSegments": [ { - "$id": "784", + "$id": "808", "kind": "method", "name": "contentType", "serializedName": "Content-Type", @@ -11154,12 +11493,12 @@ "isExactName": false }, { - "$id": "785", + "$id": "809", "kind": "path", "name": "p2", "serializedName": "p2", "type": { - "$id": "786", + "$id": "810", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -11177,12 +11516,12 @@ "crossLanguageDefinitionId": "SampleTypeSpec.helloAgain.p2", "methodParameterSegments": [ { - "$id": "787", + "$id": "811", "kind": "method", "name": "p2", "serializedName": "p2", "type": { - "$id": "788", + "$id": "812", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -11202,7 +11541,7 @@ "isExactName": false }, { - "$id": "789", + "$id": "813", "kind": "header", "name": "accept", "serializedName": "Accept", @@ -11218,7 +11557,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.helloAgain.accept", "methodParameterSegments": [ { - "$id": "790", + "$id": "814", "kind": "method", "name": "accept", "serializedName": "Accept", @@ -11239,7 +11578,7 @@ "isExactName": false }, { - "$id": "791", + "$id": "815", "kind": "body", "name": "action", "serializedName": "action", @@ -11258,7 +11597,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.helloAgain.action", "methodParameterSegments": [ { - "$id": "792", + "$id": "816", "kind": "method", "name": "action", "serializedName": "action", @@ -11315,19 +11654,19 @@ }, "parameters": [ { - "$ref": "781" + "$ref": "805" }, { - "$ref": "792" + "$ref": "816" }, { - "$ref": "784" + "$ref": "808" }, { - "$ref": "787" + "$ref": "811" }, { - "$ref": "790" + "$ref": "814" } ], "response": { @@ -11341,7 +11680,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.helloAgain" }, { - "$id": "793", + "$id": "817", "kind": "basic", "name": "noContentType", "isExactName": false, @@ -11352,7 +11691,7 @@ ], "doc": "Return hi again", "operation": { - "$id": "794", + "$id": "818", "name": "noContentType", "isExactName": false, "resourceName": "SampleTypeSpec", @@ -11360,12 +11699,12 @@ "accessibility": "public", "parameters": [ { - "$id": "795", + "$id": "819", "kind": "header", "name": "p1", "serializedName": "p1", "type": { - "$id": "796", + "$id": "820", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -11380,7 +11719,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.noContentType.p1", "methodParameterSegments": [ { - "$id": "797", + "$id": "821", "kind": "method", "name": "info", "serializedName": "info", @@ -11398,7 +11737,7 @@ "isExactName": false }, { - "$id": "798", + "$id": "822", "kind": "method", "name": "p1", "serializedName": "p1", @@ -11420,12 +11759,12 @@ "isExactName": false }, { - "$id": "799", + "$id": "823", "kind": "path", "name": "p2", "serializedName": "p2", "type": { - "$id": "800", + "$id": "824", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -11443,10 +11782,10 @@ "crossLanguageDefinitionId": "SampleTypeSpec.noContentType.p2", "methodParameterSegments": [ { - "$ref": "797" + "$ref": "821" }, { - "$id": "801", + "$id": "825", "kind": "method", "name": "p2", "serializedName": "p2", @@ -11468,7 +11807,7 @@ "isExactName": false }, { - "$id": "802", + "$id": "826", "kind": "header", "name": "contentType", "serializedName": "Content-Type", @@ -11485,7 +11824,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.noContentType.contentType", "methodParameterSegments": [ { - "$id": "803", + "$id": "827", "kind": "method", "name": "contentType", "serializedName": "Content-Type", @@ -11507,7 +11846,7 @@ "isExactName": false }, { - "$id": "804", + "$id": "828", "kind": "header", "name": "accept", "serializedName": "Accept", @@ -11523,7 +11862,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.noContentType.accept", "methodParameterSegments": [ { - "$id": "805", + "$id": "829", "kind": "method", "name": "accept", "serializedName": "Accept", @@ -11544,7 +11883,7 @@ "isExactName": false }, { - "$id": "806", + "$id": "830", "kind": "body", "name": "action", "serializedName": "action", @@ -11563,10 +11902,10 @@ "crossLanguageDefinitionId": "SampleTypeSpec.noContentType.action", "methodParameterSegments": [ { - "$ref": "797" + "$ref": "821" }, { - "$id": "807", + "$id": "831", "kind": "method", "name": "action", "serializedName": "action", @@ -11628,13 +11967,13 @@ }, "parameters": [ { - "$ref": "797" + "$ref": "821" }, { - "$ref": "803" + "$ref": "827" }, { - "$ref": "805" + "$ref": "829" } ], "response": { @@ -11648,7 +11987,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.noContentType" }, { - "$id": "808", + "$id": "832", "kind": "basic", "name": "helloDemo2", "isExactName": false, @@ -11659,7 +11998,7 @@ ], "doc": "Return hi in demo2", "operation": { - "$id": "809", + "$id": "833", "name": "helloDemo2", "isExactName": false, "resourceName": "SampleTypeSpec", @@ -11667,7 +12006,7 @@ "accessibility": "public", "parameters": [ { - "$id": "810", + "$id": "834", "kind": "header", "name": "accept", "serializedName": "Accept", @@ -11683,7 +12022,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.helloDemo2.accept", "methodParameterSegments": [ { - "$id": "811", + "$id": "835", "kind": "method", "name": "accept", "serializedName": "Accept", @@ -11740,7 +12079,7 @@ }, "parameters": [ { - "$ref": "811" + "$ref": "835" } ], "response": { @@ -11754,7 +12093,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.helloDemo2" }, { - "$id": "812", + "$id": "836", "kind": "basic", "name": "createLiteral", "isExactName": false, @@ -11765,7 +12104,7 @@ ], "doc": "Create with literal value", "operation": { - "$id": "813", + "$id": "837", "name": "createLiteral", "isExactName": false, "resourceName": "SampleTypeSpec", @@ -11773,7 +12112,7 @@ "accessibility": "public", "parameters": [ { - "$id": "814", + "$id": "838", "kind": "header", "name": "contentType", "serializedName": "Content-Type", @@ -11790,7 +12129,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.createLiteral.contentType", "methodParameterSegments": [ { - "$id": "815", + "$id": "839", "kind": "method", "name": "contentType", "serializedName": "Content-Type", @@ -11812,7 +12151,7 @@ "isExactName": false }, { - "$id": "816", + "$id": "840", "kind": "header", "name": "accept", "serializedName": "Accept", @@ -11828,7 +12167,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.createLiteral.accept", "methodParameterSegments": [ { - "$id": "817", + "$id": "841", "kind": "method", "name": "accept", "serializedName": "Accept", @@ -11849,7 +12188,7 @@ "isExactName": false }, { - "$id": "818", + "$id": "842", "kind": "body", "name": "body", "serializedName": "body", @@ -11868,7 +12207,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.createLiteral.body", "methodParameterSegments": [ { - "$id": "819", + "$id": "843", "kind": "method", "name": "body", "serializedName": "body", @@ -11929,13 +12268,13 @@ }, "parameters": [ { - "$ref": "819" + "$ref": "843" }, { - "$ref": "815" + "$ref": "839" }, { - "$ref": "817" + "$ref": "841" } ], "response": { @@ -11949,7 +12288,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.createLiteral" }, { - "$id": "820", + "$id": "844", "kind": "basic", "name": "helloLiteral", "isExactName": false, @@ -11960,7 +12299,7 @@ ], "doc": "Send literal parameters", "operation": { - "$id": "821", + "$id": "845", "name": "helloLiteral", "isExactName": false, "resourceName": "SampleTypeSpec", @@ -11968,7 +12307,7 @@ "accessibility": "public", "parameters": [ { - "$id": "822", + "$id": "846", "kind": "header", "name": "p1", "serializedName": "p1", @@ -11984,7 +12323,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.helloLiteral.p1", "methodParameterSegments": [ { - "$id": "823", + "$id": "847", "kind": "method", "name": "p1", "serializedName": "p1", @@ -12005,7 +12344,7 @@ "isExactName": false }, { - "$id": "824", + "$id": "848", "kind": "path", "name": "p2", "serializedName": "p2", @@ -12024,7 +12363,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.helloLiteral.p2", "methodParameterSegments": [ { - "$id": "825", + "$id": "849", "kind": "method", "name": "p2", "serializedName": "p2", @@ -12045,7 +12384,7 @@ "isExactName": false }, { - "$id": "826", + "$id": "850", "kind": "query", "name": "p3", "serializedName": "p3", @@ -12061,7 +12400,7 @@ "readOnly": false, "methodParameterSegments": [ { - "$id": "827", + "$id": "851", "kind": "method", "name": "p3", "serializedName": "p3", @@ -12082,7 +12421,7 @@ "isExactName": false }, { - "$id": "828", + "$id": "852", "kind": "header", "name": "accept", "serializedName": "Accept", @@ -12098,7 +12437,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.helloLiteral.accept", "methodParameterSegments": [ { - "$id": "829", + "$id": "853", "kind": "method", "name": "accept", "serializedName": "Accept", @@ -12151,16 +12490,16 @@ }, "parameters": [ { - "$ref": "823" + "$ref": "847" }, { - "$ref": "825" + "$ref": "849" }, { - "$ref": "827" + "$ref": "851" }, { - "$ref": "829" + "$ref": "853" } ], "response": { @@ -12174,7 +12513,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.helloLiteral" }, { - "$id": "830", + "$id": "854", "kind": "basic", "name": "topAction", "isExactName": false, @@ -12185,7 +12524,7 @@ ], "doc": "top level method", "operation": { - "$id": "831", + "$id": "855", "name": "topAction", "isExactName": false, "resourceName": "SampleTypeSpec", @@ -12193,17 +12532,17 @@ "accessibility": "public", "parameters": [ { - "$id": "832", + "$id": "856", "kind": "path", "name": "action", "serializedName": "action", "type": { - "$id": "833", + "$id": "857", "kind": "utcDateTime", "name": "utcDateTime", "encode": "rfc3339", "wireType": { - "$id": "834", + "$id": "858", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -12224,17 +12563,17 @@ "crossLanguageDefinitionId": "SampleTypeSpec.topAction.action", "methodParameterSegments": [ { - "$id": "835", + "$id": "859", "kind": "method", "name": "action", "serializedName": "action", "type": { - "$id": "836", + "$id": "860", "kind": "utcDateTime", "name": "utcDateTime", "encode": "rfc3339", "wireType": { - "$id": "837", + "$id": "861", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -12257,7 +12596,7 @@ "isExactName": false }, { - "$id": "838", + "$id": "862", "kind": "header", "name": "accept", "serializedName": "Accept", @@ -12273,7 +12612,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.topAction.accept", "methodParameterSegments": [ { - "$id": "839", + "$id": "863", "kind": "method", "name": "accept", "serializedName": "Accept", @@ -12326,10 +12665,10 @@ }, "parameters": [ { - "$ref": "835" + "$ref": "859" }, { - "$ref": "839" + "$ref": "863" } ], "response": { @@ -12343,7 +12682,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.topAction" }, { - "$id": "840", + "$id": "864", "kind": "basic", "name": "topAction2", "isExactName": false, @@ -12354,7 +12693,7 @@ ], "doc": "top level method2", "operation": { - "$id": "841", + "$id": "865", "name": "topAction2", "isExactName": false, "resourceName": "SampleTypeSpec", @@ -12362,7 +12701,7 @@ "accessibility": "public", "parameters": [ { - "$id": "842", + "$id": "866", "kind": "header", "name": "accept", "serializedName": "Accept", @@ -12378,7 +12717,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.topAction2.accept", "methodParameterSegments": [ { - "$id": "843", + "$id": "867", "kind": "method", "name": "accept", "serializedName": "Accept", @@ -12431,7 +12770,7 @@ }, "parameters": [ { - "$ref": "843" + "$ref": "867" } ], "response": { @@ -12445,7 +12784,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.topAction2" }, { - "$id": "844", + "$id": "868", "kind": "basic", "name": "patchAction", "isExactName": false, @@ -12456,7 +12795,7 @@ ], "doc": "top level patch", "operation": { - "$id": "845", + "$id": "869", "name": "patchAction", "isExactName": false, "resourceName": "SampleTypeSpec", @@ -12464,7 +12803,7 @@ "accessibility": "public", "parameters": [ { - "$id": "846", + "$id": "870", "kind": "header", "name": "contentType", "serializedName": "Content-Type", @@ -12481,7 +12820,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.patchAction.contentType", "methodParameterSegments": [ { - "$id": "847", + "$id": "871", "kind": "method", "name": "contentType", "serializedName": "Content-Type", @@ -12503,7 +12842,7 @@ "isExactName": false }, { - "$id": "848", + "$id": "872", "kind": "header", "name": "accept", "serializedName": "Accept", @@ -12519,7 +12858,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.patchAction.accept", "methodParameterSegments": [ { - "$id": "849", + "$id": "873", "kind": "method", "name": "accept", "serializedName": "Accept", @@ -12540,7 +12879,7 @@ "isExactName": false }, { - "$id": "850", + "$id": "874", "kind": "body", "name": "body", "serializedName": "body", @@ -12559,7 +12898,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.patchAction.body", "methodParameterSegments": [ { - "$id": "851", + "$id": "875", "kind": "method", "name": "body", "serializedName": "body", @@ -12620,13 +12959,13 @@ }, "parameters": [ { - "$ref": "851" + "$ref": "875" }, { - "$ref": "847" + "$ref": "871" }, { - "$ref": "849" + "$ref": "873" } ], "response": { @@ -12640,7 +12979,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.patchAction" }, { - "$id": "852", + "$id": "876", "kind": "basic", "name": "anonymousBody", "isExactName": false, @@ -12651,7 +12990,7 @@ ], "doc": "body parameter without body decorator", "operation": { - "$id": "853", + "$id": "877", "name": "anonymousBody", "isExactName": false, "resourceName": "SampleTypeSpec", @@ -12659,7 +12998,7 @@ "accessibility": "public", "parameters": [ { - "$id": "854", + "$id": "878", "kind": "query", "name": "requiredQueryParam", "serializedName": "requiredQueryParam", @@ -12675,7 +13014,7 @@ "readOnly": false, "methodParameterSegments": [ { - "$id": "855", + "$id": "879", "kind": "method", "name": "requiredQueryParam", "serializedName": "requiredQueryParam", @@ -12696,7 +13035,7 @@ "isExactName": false }, { - "$id": "856", + "$id": "880", "kind": "header", "name": "requiredHeader", "serializedName": "required-header", @@ -12712,7 +13051,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.anonymousBody.requiredHeader", "methodParameterSegments": [ { - "$id": "857", + "$id": "881", "kind": "method", "name": "requiredHeader", "serializedName": "required-header", @@ -12733,7 +13072,7 @@ "isExactName": false }, { - "$id": "858", + "$id": "882", "kind": "header", "name": "contentType", "serializedName": "Content-Type", @@ -12750,7 +13089,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.anonymousBody.contentType", "methodParameterSegments": [ { - "$id": "859", + "$id": "883", "kind": "method", "name": "contentType", "serializedName": "Content-Type", @@ -12772,7 +13111,7 @@ "isExactName": false }, { - "$id": "860", + "$id": "884", "kind": "header", "name": "accept", "serializedName": "Accept", @@ -12788,7 +13127,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.anonymousBody.accept", "methodParameterSegments": [ { - "$id": "861", + "$id": "885", "kind": "method", "name": "accept", "serializedName": "Accept", @@ -12809,7 +13148,7 @@ "isExactName": false }, { - "$id": "862", + "$id": "886", "kind": "body", "name": "thing", "serializedName": "thing", @@ -12828,13 +13167,13 @@ "crossLanguageDefinitionId": "SampleTypeSpec.anonymousBody.body", "methodParameterSegments": [ { - "$id": "863", + "$id": "887", "kind": "method", "name": "name", "serializedName": "name", "doc": "name of the Thing", "type": { - "$id": "864", + "$id": "888", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -12894,10 +13233,10 @@ }, "parameters": [ { - "$ref": "863" + "$ref": "887" }, { - "$id": "865", + "$id": "889", "kind": "method", "name": "requiredUnion", "serializedName": "requiredUnion", @@ -12916,7 +13255,7 @@ "isExactName": false }, { - "$id": "866", + "$id": "890", "kind": "method", "name": "requiredLiteralString", "serializedName": "requiredLiteralString", @@ -12935,7 +13274,7 @@ "isExactName": false }, { - "$id": "867", + "$id": "891", "kind": "method", "name": "requiredNullableString", "serializedName": "requiredNullableString", @@ -12954,7 +13293,7 @@ "isExactName": false }, { - "$id": "868", + "$id": "892", "kind": "method", "name": "optionalNullableString", "serializedName": "optionalNullableString", @@ -12973,7 +13312,7 @@ "isExactName": false }, { - "$id": "869", + "$id": "893", "kind": "method", "name": "requiredLiteralInt", "serializedName": "requiredLiteralInt", @@ -12992,7 +13331,7 @@ "isExactName": false }, { - "$id": "870", + "$id": "894", "kind": "method", "name": "requiredLiteralFloat", "serializedName": "requiredLiteralFloat", @@ -13011,7 +13350,7 @@ "isExactName": false }, { - "$id": "871", + "$id": "895", "kind": "method", "name": "requiredLiteralBool", "serializedName": "requiredLiteralBool", @@ -13030,19 +13369,19 @@ "isExactName": false }, { - "$id": "872", + "$id": "896", "kind": "method", "name": "optionalLiteralString", "serializedName": "optionalLiteralString", "doc": "optional literal string", "type": { - "$id": "873", + "$id": "897", "kind": "enum", "name": "ThingOptionalLiteralString", "apiVersions": [], "crossLanguageDefinitionId": "", "valueType": { - "$id": "874", + "$id": "898", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -13050,12 +13389,12 @@ }, "values": [ { - "$id": "875", + "$id": "899", "kind": "enumvalue", "name": "reject", "value": "reject", "valueType": { - "$id": "876", + "$id": "900", "kind": "string", "decorators": [], "doc": "A sequence of textual characters.", @@ -13063,7 +13402,7 @@ "crossLanguageDefinitionId": "TypeSpec.string" }, "enumType": { - "$ref": "873" + "$ref": "897" }, "decorators": [], "isExactName": false @@ -13087,7 +13426,7 @@ "isExactName": false }, { - "$id": "877", + "$id": "901", "kind": "method", "name": "requiredNullableLiteralString", "serializedName": "requiredNullableLiteralString", @@ -13106,19 +13445,19 @@ "isExactName": false }, { - "$id": "878", + "$id": "902", "kind": "method", "name": "optionalLiteralInt", "serializedName": "optionalLiteralInt", "doc": "optional literal int", "type": { - "$id": "879", + "$id": "903", "kind": "enum", "name": "ThingOptionalLiteralInt", "apiVersions": [], "crossLanguageDefinitionId": "", "valueType": { - "$id": "880", + "$id": "904", "kind": "int32", "name": "int32", "crossLanguageDefinitionId": "TypeSpec.int32", @@ -13126,12 +13465,12 @@ }, "values": [ { - "$id": "881", + "$id": "905", "kind": "enumvalue", "name": "456", "value": 456, "valueType": { - "$id": "882", + "$id": "906", "kind": "int32", "decorators": [], "doc": "A 32-bit integer. (`-2,147,483,648` to `2,147,483,647`)", @@ -13139,7 +13478,7 @@ "crossLanguageDefinitionId": "TypeSpec.int32" }, "enumType": { - "$ref": "879" + "$ref": "903" }, "decorators": [], "isExactName": false @@ -13163,19 +13502,19 @@ "isExactName": false }, { - "$id": "883", + "$id": "907", "kind": "method", "name": "optionalLiteralFloat", "serializedName": "optionalLiteralFloat", "doc": "optional literal float", "type": { - "$id": "884", + "$id": "908", "kind": "enum", "name": "ThingOptionalLiteralFloat", "apiVersions": [], "crossLanguageDefinitionId": "", "valueType": { - "$id": "885", + "$id": "909", "kind": "float32", "name": "float32", "crossLanguageDefinitionId": "TypeSpec.float32", @@ -13183,12 +13522,12 @@ }, "values": [ { - "$id": "886", + "$id": "910", "kind": "enumvalue", "name": "4.56", "value": 4.56, "valueType": { - "$id": "887", + "$id": "911", "kind": "float32", "decorators": [], "doc": "A 32 bit floating point number. (`±1.5 x 10^−45` to `±3.4 x 10^38`)", @@ -13196,7 +13535,7 @@ "crossLanguageDefinitionId": "TypeSpec.float32" }, "enumType": { - "$ref": "884" + "$ref": "908" }, "decorators": [], "isExactName": false @@ -13220,7 +13559,7 @@ "isExactName": false }, { - "$id": "888", + "$id": "912", "kind": "method", "name": "optionalLiteralBool", "serializedName": "optionalLiteralBool", @@ -13239,13 +13578,13 @@ "isExactName": false }, { - "$id": "889", + "$id": "913", "kind": "method", "name": "requiredBadDescription", "serializedName": "requiredBadDescription", "doc": "description with xml <|endoftext|>", "type": { - "$id": "890", + "$id": "914", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -13262,7 +13601,7 @@ "isExactName": false }, { - "$id": "891", + "$id": "915", "kind": "method", "name": "optionalNullableList", "serializedName": "optionalNullableList", @@ -13281,7 +13620,7 @@ "isExactName": false }, { - "$id": "892", + "$id": "916", "kind": "method", "name": "requiredNullableList", "serializedName": "requiredNullableList", @@ -13300,13 +13639,13 @@ "isExactName": false }, { - "$id": "893", + "$id": "917", "kind": "method", "name": "propertyWithSpecialDocs", "serializedName": "propertyWithSpecialDocs", "doc": "This tests:\n- Simple bullet point. This bullet point is going to be very long to test how text wrapping is handled in bullet points within documentation comments. It should properly indent the wrapped lines.\n- Another bullet point with **bold text**. This bullet point is also intentionally long to see how the formatting is preserved when the text wraps onto multiple lines in the generated documentation.\n- Third bullet point with *italic text*. Similar to the previous points, this one is extended to ensure that the wrapping and formatting are correctly applied in the output.\n- Complex bullet point with **bold** and *italic* combined. This bullet point combines both bold and italic formatting and is long enough to test the wrapping behavior in such cases.\n- **Bold bullet point**: A bullet point that is entirely bolded. This point is also made lengthy to observe how the bold formatting is maintained across wrapped lines.\n- *Italic bullet point*: A bullet point that is entirely italicized. This final point is extended to verify that italic formatting is correctly applied even when the text spans multiple lines.", "type": { - "$id": "894", + "$id": "918", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -13323,16 +13662,16 @@ "isExactName": false }, { - "$ref": "855" + "$ref": "879" }, { - "$ref": "857" + "$ref": "881" }, { - "$ref": "859" + "$ref": "883" }, { - "$ref": "861" + "$ref": "885" } ], "response": { @@ -13346,7 +13685,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.anonymousBody" }, { - "$id": "895", + "$id": "919", "kind": "basic", "name": "friendlyModel", "isExactName": false, @@ -13357,7 +13696,7 @@ ], "doc": "Model can have its friendly name", "operation": { - "$id": "896", + "$id": "920", "name": "friendlyModel", "isExactName": false, "resourceName": "SampleTypeSpec", @@ -13365,7 +13704,7 @@ "accessibility": "public", "parameters": [ { - "$id": "897", + "$id": "921", "kind": "header", "name": "contentType", "serializedName": "Content-Type", @@ -13382,7 +13721,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.friendlyModel.contentType", "methodParameterSegments": [ { - "$id": "898", + "$id": "922", "kind": "method", "name": "contentType", "serializedName": "Content-Type", @@ -13404,7 +13743,7 @@ "isExactName": false }, { - "$id": "899", + "$id": "923", "kind": "header", "name": "accept", "serializedName": "Accept", @@ -13420,7 +13759,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.friendlyModel.accept", "methodParameterSegments": [ { - "$id": "900", + "$id": "924", "kind": "method", "name": "accept", "serializedName": "Accept", @@ -13441,7 +13780,7 @@ "isExactName": false }, { - "$id": "901", + "$id": "925", "kind": "body", "name": "friend", "serializedName": "friend", @@ -13460,13 +13799,13 @@ "crossLanguageDefinitionId": "SampleTypeSpec.friendlyModel.body", "methodParameterSegments": [ { - "$id": "902", + "$id": "926", "kind": "method", "name": "name", "serializedName": "name", "doc": "name of the NotFriend", "type": { - "$id": "903", + "$id": "927", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -13526,13 +13865,13 @@ }, "parameters": [ { - "$ref": "902" + "$ref": "926" }, { - "$ref": "898" + "$ref": "922" }, { - "$ref": "900" + "$ref": "924" } ], "response": { @@ -13546,7 +13885,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.friendlyModel" }, { - "$id": "904", + "$id": "928", "kind": "basic", "name": "addTimeHeader", "isExactName": false, @@ -13556,24 +13895,24 @@ "2024-08-16-preview" ], "operation": { - "$id": "905", + "$id": "929", "name": "addTimeHeader", "isExactName": false, "resourceName": "SampleTypeSpec", "accessibility": "public", "parameters": [ { - "$id": "906", + "$id": "930", "kind": "header", "name": "repeatabilityFirstSent", "serializedName": "Repeatability-First-Sent", "type": { - "$id": "907", + "$id": "931", "kind": "utcDateTime", "name": "utcDateTime", "encode": "rfc7231", "wireType": { - "$id": "908", + "$id": "932", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -13591,17 +13930,17 @@ "crossLanguageDefinitionId": "SampleTypeSpec.addTimeHeader.repeatabilityFirstSent", "methodParameterSegments": [ { - "$id": "909", + "$id": "933", "kind": "method", "name": "repeatabilityFirstSent", "serializedName": "Repeatability-First-Sent", "type": { - "$id": "910", + "$id": "934", "kind": "utcDateTime", "name": "utcDateTime", "encode": "rfc7231", "wireType": { - "$id": "911", + "$id": "935", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -13646,7 +13985,7 @@ }, "parameters": [ { - "$ref": "909" + "$ref": "933" } ], "response": {}, @@ -13656,7 +13995,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.addTimeHeader" }, { - "$id": "912", + "$id": "936", "kind": "basic", "name": "projectedNameModel", "isExactName": false, @@ -13667,7 +14006,7 @@ ], "doc": "Model can have its projected name", "operation": { - "$id": "913", + "$id": "937", "name": "projectedNameModel", "isExactName": false, "resourceName": "SampleTypeSpec", @@ -13675,7 +14014,7 @@ "accessibility": "public", "parameters": [ { - "$id": "914", + "$id": "938", "kind": "header", "name": "contentType", "serializedName": "Content-Type", @@ -13692,7 +14031,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.projectedNameModel.contentType", "methodParameterSegments": [ { - "$id": "915", + "$id": "939", "kind": "method", "name": "contentType", "serializedName": "Content-Type", @@ -13714,7 +14053,7 @@ "isExactName": false }, { - "$id": "916", + "$id": "940", "kind": "header", "name": "accept", "serializedName": "Accept", @@ -13730,7 +14069,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.projectedNameModel.accept", "methodParameterSegments": [ { - "$id": "917", + "$id": "941", "kind": "method", "name": "accept", "serializedName": "Accept", @@ -13751,7 +14090,7 @@ "isExactName": false }, { - "$id": "918", + "$id": "942", "kind": "body", "name": "renamedModel", "serializedName": "renamedModel", @@ -13770,13 +14109,13 @@ "crossLanguageDefinitionId": "SampleTypeSpec.projectedNameModel.body", "methodParameterSegments": [ { - "$id": "919", + "$id": "943", "kind": "method", "name": "otherName", "serializedName": "otherName", "doc": "name of the ModelWithClientName", "type": { - "$id": "920", + "$id": "944", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -13836,13 +14175,13 @@ }, "parameters": [ { - "$ref": "919" + "$ref": "943" }, { - "$ref": "915" + "$ref": "939" }, { - "$ref": "917" + "$ref": "941" } ], "response": { @@ -13856,7 +14195,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.projectedNameModel" }, { - "$id": "921", + "$id": "945", "kind": "basic", "name": "returnsAnonymousModel", "isExactName": false, @@ -13867,7 +14206,7 @@ ], "doc": "return anonymous model", "operation": { - "$id": "922", + "$id": "946", "name": "returnsAnonymousModel", "isExactName": false, "resourceName": "SampleTypeSpec", @@ -13875,7 +14214,7 @@ "accessibility": "public", "parameters": [ { - "$id": "923", + "$id": "947", "kind": "header", "name": "accept", "serializedName": "Accept", @@ -13891,7 +14230,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.returnsAnonymousModel.accept", "methodParameterSegments": [ { - "$id": "924", + "$id": "948", "kind": "method", "name": "accept", "serializedName": "Accept", @@ -13944,7 +14283,7 @@ }, "parameters": [ { - "$ref": "924" + "$ref": "948" } ], "response": { @@ -13958,7 +14297,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.returnsAnonymousModel" }, { - "$id": "925", + "$id": "949", "kind": "basic", "name": "getUnknownValue", "isExactName": false, @@ -13969,7 +14308,7 @@ ], "doc": "get extensible enum", "operation": { - "$id": "926", + "$id": "950", "name": "getUnknownValue", "isExactName": false, "resourceName": "SampleTypeSpec", @@ -13977,7 +14316,7 @@ "accessibility": "public", "parameters": [ { - "$id": "927", + "$id": "951", "kind": "header", "name": "accept", "serializedName": "Accept", @@ -13993,7 +14332,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.getUnknownValue.accept", "methodParameterSegments": [ { - "$id": "928", + "$id": "952", "kind": "method", "name": "accept", "serializedName": "Accept", @@ -14042,7 +14381,7 @@ }, "parameters": [ { - "$ref": "928" + "$ref": "952" } ], "response": { @@ -14056,7 +14395,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.getUnknownValue" }, { - "$id": "929", + "$id": "953", "kind": "basic", "name": "internalProtocol", "isExactName": false, @@ -14067,7 +14406,7 @@ ], "doc": "When set protocol false and convenient true, then the protocol method should be internal", "operation": { - "$id": "930", + "$id": "954", "name": "internalProtocol", "isExactName": false, "resourceName": "SampleTypeSpec", @@ -14075,7 +14414,7 @@ "accessibility": "public", "parameters": [ { - "$id": "931", + "$id": "955", "kind": "header", "name": "contentType", "serializedName": "Content-Type", @@ -14092,7 +14431,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.internalProtocol.contentType", "methodParameterSegments": [ { - "$id": "932", + "$id": "956", "kind": "method", "name": "contentType", "serializedName": "Content-Type", @@ -14114,7 +14453,7 @@ "isExactName": false }, { - "$id": "933", + "$id": "957", "kind": "header", "name": "accept", "serializedName": "Accept", @@ -14130,7 +14469,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.internalProtocol.accept", "methodParameterSegments": [ { - "$id": "934", + "$id": "958", "kind": "method", "name": "accept", "serializedName": "Accept", @@ -14151,7 +14490,7 @@ "isExactName": false }, { - "$id": "935", + "$id": "959", "kind": "body", "name": "body", "serializedName": "body", @@ -14170,7 +14509,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.internalProtocol.body", "methodParameterSegments": [ { - "$id": "936", + "$id": "960", "kind": "method", "name": "body", "serializedName": "body", @@ -14231,13 +14570,13 @@ }, "parameters": [ { - "$ref": "936" + "$ref": "960" }, { - "$ref": "932" + "$ref": "956" }, { - "$ref": "934" + "$ref": "958" } ], "response": { @@ -14251,7 +14590,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.internalProtocol" }, { - "$id": "937", + "$id": "961", "kind": "basic", "name": "stillConvenient", "isExactName": false, @@ -14262,7 +14601,7 @@ ], "doc": "When set protocol false and convenient true, the convenient method should be generated even it has the same signature as protocol one", "operation": { - "$id": "938", + "$id": "962", "name": "stillConvenient", "isExactName": false, "resourceName": "SampleTypeSpec", @@ -14297,7 +14636,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.stillConvenient" }, { - "$id": "939", + "$id": "963", "kind": "basic", "name": "headAsBoolean", "isExactName": false, @@ -14308,7 +14647,7 @@ ], "doc": "head as boolean.", "operation": { - "$id": "940", + "$id": "964", "name": "headAsBoolean", "isExactName": false, "resourceName": "SampleTypeSpec", @@ -14316,12 +14655,12 @@ "accessibility": "public", "parameters": [ { - "$id": "941", + "$id": "965", "kind": "path", "name": "id", "serializedName": "id", "type": { - "$id": "942", + "$id": "966", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -14339,12 +14678,12 @@ "crossLanguageDefinitionId": "SampleTypeSpec.headAsBoolean.id", "methodParameterSegments": [ { - "$id": "943", + "$id": "967", "kind": "method", "name": "id", "serializedName": "id", "type": { - "$id": "944", + "$id": "968", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -14386,7 +14725,7 @@ }, "parameters": [ { - "$ref": "943" + "$ref": "967" } ], "response": {}, @@ -14396,7 +14735,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.headAsBoolean" }, { - "$id": "945", + "$id": "969", "kind": "basic", "name": "WithApiVersion", "isExactName": false, @@ -14407,7 +14746,7 @@ ], "doc": "Return hi again", "operation": { - "$id": "946", + "$id": "970", "name": "WithApiVersion", "isExactName": false, "resourceName": "SampleTypeSpec", @@ -14415,12 +14754,12 @@ "accessibility": "public", "parameters": [ { - "$id": "947", + "$id": "971", "kind": "header", "name": "p1", "serializedName": "p1", "type": { - "$id": "948", + "$id": "972", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -14435,12 +14774,12 @@ "crossLanguageDefinitionId": "SampleTypeSpec.WithApiVersion.p1", "methodParameterSegments": [ { - "$id": "949", + "$id": "973", "kind": "method", "name": "p1", "serializedName": "p1", "type": { - "$id": "950", + "$id": "974", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -14460,12 +14799,12 @@ "isExactName": false }, { - "$id": "951", + "$id": "975", "kind": "query", "name": "apiVersion", "serializedName": "apiVersion", "type": { - "$id": "952", + "$id": "976", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -14475,7 +14814,7 @@ "explode": false, "defaultValue": { "type": { - "$id": "953", + "$id": "977", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string" @@ -14489,12 +14828,12 @@ "readOnly": false, "methodParameterSegments": [ { - "$id": "954", + "$id": "978", "kind": "method", "name": "apiVersion", "serializedName": "apiVersion", "type": { - "$id": "955", + "$id": "979", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -14504,7 +14843,7 @@ "isApiVersion": true, "defaultValue": { "type": { - "$id": "956", + "$id": "980", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string" @@ -14545,7 +14884,7 @@ }, "parameters": [ { - "$ref": "949" + "$ref": "973" } ], "response": {}, @@ -14555,7 +14894,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.WithApiVersion" }, { - "$id": "957", + "$id": "981", "kind": "paging", "name": "ListWithNextLink", "isExactName": false, @@ -14566,7 +14905,7 @@ ], "doc": "List things with nextlink", "operation": { - "$id": "958", + "$id": "982", "name": "ListWithNextLink", "isExactName": false, "resourceName": "SampleTypeSpec", @@ -14574,7 +14913,7 @@ "accessibility": "public", "parameters": [ { - "$id": "959", + "$id": "983", "kind": "header", "name": "accept", "serializedName": "Accept", @@ -14590,7 +14929,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.ListWithNextLink.accept", "methodParameterSegments": [ { - "$id": "960", + "$id": "984", "kind": "method", "name": "accept", "serializedName": "Accept", @@ -14643,7 +14982,7 @@ }, "parameters": [ { - "$ref": "960" + "$ref": "984" } ], "response": { @@ -14673,7 +15012,7 @@ } }, { - "$id": "961", + "$id": "985", "kind": "paging", "name": "ListWithStringNextLink", "isExactName": false, @@ -14684,7 +15023,7 @@ ], "doc": "List things with nextlink", "operation": { - "$id": "962", + "$id": "986", "name": "ListWithStringNextLink", "isExactName": false, "resourceName": "SampleTypeSpec", @@ -14692,7 +15031,7 @@ "accessibility": "public", "parameters": [ { - "$id": "963", + "$id": "987", "kind": "header", "name": "accept", "serializedName": "Accept", @@ -14708,7 +15047,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.ListWithStringNextLink.accept", "methodParameterSegments": [ { - "$id": "964", + "$id": "988", "kind": "method", "name": "accept", "serializedName": "Accept", @@ -14761,7 +15100,7 @@ }, "parameters": [ { - "$ref": "964" + "$ref": "988" } ], "response": { @@ -14791,7 +15130,7 @@ } }, { - "$id": "965", + "$id": "989", "kind": "paging", "name": "ListWithContinuationToken", "isExactName": false, @@ -14802,7 +15141,7 @@ ], "doc": "List things with continuation token", "operation": { - "$id": "966", + "$id": "990", "name": "ListWithContinuationToken", "isExactName": false, "resourceName": "SampleTypeSpec", @@ -14810,12 +15149,12 @@ "accessibility": "public", "parameters": [ { - "$id": "967", + "$id": "991", "kind": "query", "name": "token", "serializedName": "token", "type": { - "$id": "968", + "$id": "992", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -14830,12 +15169,12 @@ "readOnly": false, "methodParameterSegments": [ { - "$id": "969", + "$id": "993", "kind": "method", "name": "token", "serializedName": "token", "type": { - "$id": "970", + "$id": "994", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -14855,7 +15194,7 @@ "isExactName": false }, { - "$id": "971", + "$id": "995", "kind": "header", "name": "accept", "serializedName": "Accept", @@ -14871,7 +15210,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.ListWithContinuationToken.accept", "methodParameterSegments": [ { - "$id": "972", + "$id": "996", "kind": "method", "name": "accept", "serializedName": "Accept", @@ -14924,10 +15263,10 @@ }, "parameters": [ { - "$ref": "969" + "$ref": "993" }, { - "$ref": "972" + "$ref": "996" } ], "response": { @@ -14948,7 +15287,7 @@ ], "continuationToken": { "parameter": { - "$ref": "967" + "$ref": "991" }, "responseSegments": [ "nextToken" @@ -14959,7 +15298,7 @@ } }, { - "$id": "973", + "$id": "997", "kind": "paging", "name": "ListWithContinuationTokenHeaderResponse", "isExactName": false, @@ -14970,7 +15309,7 @@ ], "doc": "List things with continuation token header response", "operation": { - "$id": "974", + "$id": "998", "name": "ListWithContinuationTokenHeaderResponse", "isExactName": false, "resourceName": "SampleTypeSpec", @@ -14978,12 +15317,12 @@ "accessibility": "public", "parameters": [ { - "$id": "975", + "$id": "999", "kind": "query", "name": "token", "serializedName": "token", "type": { - "$id": "976", + "$id": "1000", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -14998,12 +15337,12 @@ "readOnly": false, "methodParameterSegments": [ { - "$id": "977", + "$id": "1001", "kind": "method", "name": "token", "serializedName": "token", "type": { - "$id": "978", + "$id": "1002", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -15023,7 +15362,7 @@ "isExactName": false }, { - "$id": "979", + "$id": "1003", "kind": "header", "name": "accept", "serializedName": "Accept", @@ -15039,7 +15378,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.ListWithContinuationTokenHeaderResponse.accept", "methodParameterSegments": [ { - "$id": "980", + "$id": "1004", "kind": "method", "name": "accept", "serializedName": "Accept", @@ -15073,7 +15412,7 @@ "name": "nextToken", "nameInResponse": "next-token", "type": { - "$id": "981", + "$id": "1005", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -15104,10 +15443,10 @@ }, "parameters": [ { - "$ref": "977" + "$ref": "1001" }, { - "$ref": "980" + "$ref": "1004" } ], "response": { @@ -15128,7 +15467,7 @@ ], "continuationToken": { "parameter": { - "$ref": "975" + "$ref": "999" }, "responseSegments": [ "next-token" @@ -15139,7 +15478,7 @@ } }, { - "$id": "982", + "$id": "1006", "kind": "paging", "name": "ListWithPaging", "isExactName": false, @@ -15150,7 +15489,7 @@ ], "doc": "List things with paging", "operation": { - "$id": "983", + "$id": "1007", "name": "ListWithPaging", "isExactName": false, "resourceName": "SampleTypeSpec", @@ -15158,7 +15497,7 @@ "accessibility": "public", "parameters": [ { - "$id": "984", + "$id": "1008", "kind": "header", "name": "accept", "serializedName": "Accept", @@ -15174,7 +15513,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.ListWithPaging.accept", "methodParameterSegments": [ { - "$id": "985", + "$id": "1009", "kind": "method", "name": "accept", "serializedName": "Accept", @@ -15227,7 +15566,7 @@ }, "parameters": [ { - "$ref": "985" + "$ref": "1009" } ], "response": { @@ -15250,7 +15589,7 @@ } }, { - "$id": "986", + "$id": "1010", "kind": "basic", "name": "EmbeddedParameters", "isExactName": false, @@ -15261,7 +15600,7 @@ ], "doc": "An operation with embedded parameters within the body", "operation": { - "$id": "987", + "$id": "1011", "name": "EmbeddedParameters", "isExactName": false, "resourceName": "SampleTypeSpec", @@ -15269,13 +15608,13 @@ "accessibility": "public", "parameters": [ { - "$id": "988", + "$id": "1012", "kind": "header", "name": "requiredHeader", "serializedName": "required-header", "doc": "required header parameter", "type": { - "$id": "989", + "$id": "1013", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -15290,7 +15629,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.ModelWithEmbeddedNonBodyParameters.requiredHeader", "methodParameterSegments": [ { - "$id": "990", + "$id": "1014", "kind": "method", "name": "body", "serializedName": "body", @@ -15308,7 +15647,7 @@ "isExactName": false }, { - "$id": "991", + "$id": "1015", "kind": "method", "name": "requiredHeader", "serializedName": "requiredHeader", @@ -15330,13 +15669,13 @@ "isExactName": false }, { - "$id": "992", + "$id": "1016", "kind": "header", "name": "optionalHeader", "serializedName": "optional-header", "doc": "optional header parameter", "type": { - "$id": "993", + "$id": "1017", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -15351,10 +15690,10 @@ "crossLanguageDefinitionId": "SampleTypeSpec.ModelWithEmbeddedNonBodyParameters.optionalHeader", "methodParameterSegments": [ { - "$ref": "990" + "$ref": "1014" }, { - "$id": "994", + "$id": "1018", "kind": "method", "name": "optionalHeader", "serializedName": "optionalHeader", @@ -15376,13 +15715,13 @@ "isExactName": false }, { - "$id": "995", + "$id": "1019", "kind": "query", "name": "requiredQuery", "serializedName": "requiredQuery", "doc": "required query parameter", "type": { - "$id": "996", + "$id": "1020", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -15397,10 +15736,10 @@ "readOnly": false, "methodParameterSegments": [ { - "$ref": "990" + "$ref": "1014" }, { - "$id": "997", + "$id": "1021", "kind": "method", "name": "requiredQuery", "serializedName": "requiredQuery", @@ -15422,13 +15761,13 @@ "isExactName": false }, { - "$id": "998", + "$id": "1022", "kind": "query", "name": "optionalQuery", "serializedName": "optionalQuery", "doc": "optional query parameter", "type": { - "$id": "999", + "$id": "1023", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -15443,10 +15782,10 @@ "readOnly": false, "methodParameterSegments": [ { - "$ref": "990" + "$ref": "1014" }, { - "$id": "1000", + "$id": "1024", "kind": "method", "name": "optionalQuery", "serializedName": "optionalQuery", @@ -15468,7 +15807,7 @@ "isExactName": false }, { - "$id": "1001", + "$id": "1025", "kind": "header", "name": "contentType", "serializedName": "Content-Type", @@ -15485,7 +15824,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.EmbeddedParameters.contentType", "methodParameterSegments": [ { - "$id": "1002", + "$id": "1026", "kind": "method", "name": "contentType", "serializedName": "Content-Type", @@ -15507,7 +15846,7 @@ "isExactName": false }, { - "$id": "1003", + "$id": "1027", "kind": "body", "name": "body", "serializedName": "body", @@ -15526,7 +15865,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.EmbeddedParameters.body", "methodParameterSegments": [ { - "$ref": "990" + "$ref": "1014" } ], "isExactName": false, @@ -15562,10 +15901,10 @@ }, "parameters": [ { - "$ref": "990" + "$ref": "1014" }, { - "$ref": "1002" + "$ref": "1026" } ], "response": {}, @@ -15575,7 +15914,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.EmbeddedParameters" }, { - "$id": "1004", + "$id": "1028", "kind": "basic", "name": "DynamicModelOperation", "isExactName": false, @@ -15586,7 +15925,7 @@ ], "doc": "An operation with a dynamic model", "operation": { - "$id": "1005", + "$id": "1029", "name": "DynamicModelOperation", "isExactName": false, "resourceName": "SampleTypeSpec", @@ -15594,7 +15933,7 @@ "accessibility": "public", "parameters": [ { - "$id": "1006", + "$id": "1030", "kind": "header", "name": "contentType", "serializedName": "Content-Type", @@ -15611,7 +15950,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.DynamicModelOperation.contentType", "methodParameterSegments": [ { - "$id": "1007", + "$id": "1031", "kind": "method", "name": "contentType", "serializedName": "Content-Type", @@ -15633,7 +15972,7 @@ "isExactName": false }, { - "$id": "1008", + "$id": "1032", "kind": "body", "name": "body", "serializedName": "body", @@ -15652,7 +15991,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.DynamicModelOperation.body", "methodParameterSegments": [ { - "$id": "1009", + "$id": "1033", "kind": "method", "name": "body", "serializedName": "body", @@ -15709,10 +16048,10 @@ }, "parameters": [ { - "$ref": "1009" + "$ref": "1033" }, { - "$ref": "1007" + "$ref": "1031" } ], "response": {}, @@ -15722,7 +16061,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.DynamicModelOperation" }, { - "$id": "1010", + "$id": "1034", "kind": "basic", "name": "GetXmlAdvancedModel", "isExactName": false, @@ -15733,7 +16072,7 @@ ], "doc": "Get an advanced XML model with various property types", "operation": { - "$id": "1011", + "$id": "1035", "name": "GetXmlAdvancedModel", "isExactName": false, "resourceName": "SampleTypeSpec", @@ -15741,7 +16080,7 @@ "accessibility": "public", "parameters": [ { - "$id": "1012", + "$id": "1036", "kind": "header", "name": "accept", "serializedName": "Accept", @@ -15757,7 +16096,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.GetXmlAdvancedModel.accept", "methodParameterSegments": [ { - "$id": "1013", + "$id": "1037", "kind": "method", "name": "accept", "serializedName": "Accept", @@ -15818,7 +16157,7 @@ }, "parameters": [ { - "$ref": "1013" + "$ref": "1037" } ], "response": { @@ -15832,7 +16171,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.GetXmlAdvancedModel" }, { - "$id": "1014", + "$id": "1038", "kind": "basic", "name": "UpdateXmlAdvancedModel", "isExactName": false, @@ -15843,7 +16182,7 @@ ], "doc": "Update an advanced XML model with various property types", "operation": { - "$id": "1015", + "$id": "1039", "name": "UpdateXmlAdvancedModel", "isExactName": false, "resourceName": "SampleTypeSpec", @@ -15851,7 +16190,7 @@ "accessibility": "public", "parameters": [ { - "$id": "1016", + "$id": "1040", "kind": "header", "name": "contentType", "serializedName": "Content-Type", @@ -15867,7 +16206,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.UpdateXmlAdvancedModel.contentType", "methodParameterSegments": [ { - "$id": "1017", + "$id": "1041", "kind": "method", "name": "contentType", "serializedName": "Content-Type", @@ -15888,7 +16227,7 @@ "isExactName": false }, { - "$id": "1018", + "$id": "1042", "kind": "header", "name": "accept", "serializedName": "Accept", @@ -15904,7 +16243,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.UpdateXmlAdvancedModel.accept", "methodParameterSegments": [ { - "$id": "1019", + "$id": "1043", "kind": "method", "name": "accept", "serializedName": "Accept", @@ -15925,7 +16264,7 @@ "isExactName": false }, { - "$id": "1020", + "$id": "1044", "kind": "body", "name": "body", "serializedName": "body", @@ -15944,7 +16283,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.UpdateXmlAdvancedModel.body", "methodParameterSegments": [ { - "$id": "1021", + "$id": "1045", "kind": "method", "name": "body", "serializedName": "body", @@ -16013,13 +16352,13 @@ }, "parameters": [ { - "$ref": "1021" + "$ref": "1045" }, { - "$ref": "1017" + "$ref": "1041" }, { - "$ref": "1019" + "$ref": "1043" } ], "response": { @@ -16033,7 +16372,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.UpdateXmlAdvancedModel" }, { - "$id": "1022", + "$id": "1046", "kind": "basic", "name": "uploadCat", "isExactName": false, @@ -16043,14 +16382,14 @@ "2024-08-16-preview" ], "operation": { - "$id": "1023", + "$id": "1047", "name": "uploadCat", "isExactName": false, "resourceName": "SampleTypeSpec", "accessibility": "public", "parameters": [ { - "$id": "1024", + "$id": "1048", "kind": "header", "name": "contentType", "serializedName": "Content-Type", @@ -16066,7 +16405,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.uploadCat.contentType", "methodParameterSegments": [ { - "$id": "1025", + "$id": "1049", "kind": "method", "name": "contentType", "serializedName": "Content-Type", @@ -16087,7 +16426,7 @@ "isExactName": false }, { - "$id": "1026", + "$id": "1050", "kind": "body", "name": "body", "serializedName": "body", @@ -16106,7 +16445,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.uploadCat.body", "methodParameterSegments": [ { - "$id": "1027", + "$id": "1051", "kind": "method", "name": "body", "serializedName": "body", @@ -16153,10 +16492,10 @@ }, "parameters": [ { - "$ref": "1025" + "$ref": "1049" }, { - "$ref": "1027" + "$ref": "1051" } ], "response": {}, @@ -16166,7 +16505,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.uploadCat" }, { - "$id": "1028", + "$id": "1052", "kind": "basic", "name": "sendJsonLines", "isExactName": false, @@ -16176,14 +16515,14 @@ "2024-08-16-preview" ], "operation": { - "$id": "1029", + "$id": "1053", "name": "sendJsonLines", "isExactName": false, "resourceName": "SampleTypeSpec", "accessibility": "public", "parameters": [ { - "$id": "1030", + "$id": "1054", "kind": "header", "name": "contentType", "serializedName": "Content-Type", @@ -16199,12 +16538,12 @@ "crossLanguageDefinitionId": "TypeSpec.Http.Streams.JsonlStream.contentType", "methodParameterSegments": [ { - "$id": "1031", + "$id": "1055", "kind": "method", "name": "stream", "serializedName": "stream", "type": { - "$id": "1032", + "$id": "1056", "kind": "streaming", "name": "JsonlStreamStreamingItem", "valueType": { @@ -16227,7 +16566,7 @@ "isExactName": false }, { - "$id": "1033", + "$id": "1057", "kind": "method", "name": "contentType", "serializedName": "contentType", @@ -16248,12 +16587,12 @@ "isExactName": false }, { - "$id": "1034", + "$id": "1058", "kind": "body", "name": "body", "serializedName": "body", "type": { - "$id": "1035", + "$id": "1059", "kind": "streaming", "name": "JsonlStreamStreamingItem", "valueType": { @@ -16277,10 +16616,10 @@ "crossLanguageDefinitionId": "TypeSpec.Http.Streams.JsonlStream.body", "methodParameterSegments": [ { - "$ref": "1031" + "$ref": "1055" }, { - "$id": "1036", + "$id": "1060", "kind": "method", "name": "body", "serializedName": "body", @@ -16331,7 +16670,7 @@ }, "parameters": [ { - "$ref": "1031" + "$ref": "1055" } ], "response": {}, @@ -16341,7 +16680,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.sendJsonLines" }, { - "$id": "1037", + "$id": "1061", "kind": "basic", "name": "receiveJsonLines", "isExactName": false, @@ -16351,14 +16690,14 @@ "2024-08-16-preview" ], "operation": { - "$id": "1038", + "$id": "1062", "name": "receiveJsonLines", "isExactName": false, "resourceName": "SampleTypeSpec", "accessibility": "public", "parameters": [ { - "$id": "1039", + "$id": "1063", "kind": "header", "name": "accept", "serializedName": "Accept", @@ -16374,7 +16713,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.receiveJsonLines.accept", "methodParameterSegments": [ { - "$id": "1040", + "$id": "1064", "kind": "method", "name": "accept", "serializedName": "Accept", @@ -16401,7 +16740,7 @@ 200 ], "bodyType": { - "$id": "1041", + "$id": "1065", "kind": "streaming", "name": "JsonlStreamStreamingItem", "valueType": { @@ -16445,12 +16784,12 @@ }, "parameters": [ { - "$ref": "1040" + "$ref": "1064" } ], "response": { "type": { - "$id": "1042", + "$id": "1066", "kind": "streaming", "name": "JsonlStreamStreamingItem", "valueType": { @@ -16469,7 +16808,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.receiveJsonLines" }, { - "$id": "1043", + "$id": "1067", "kind": "basic", "name": "receiveSse", "isExactName": false, @@ -16479,14 +16818,14 @@ "2024-08-16-preview" ], "operation": { - "$id": "1044", + "$id": "1068", "name": "receiveSse", "isExactName": false, "resourceName": "SampleTypeSpec", "accessibility": "public", "parameters": [ { - "$id": "1045", + "$id": "1069", "kind": "header", "name": "accept", "serializedName": "Accept", @@ -16502,7 +16841,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.receiveSse.accept", "methodParameterSegments": [ { - "$id": "1046", + "$id": "1070", "kind": "method", "name": "accept", "serializedName": "Accept", @@ -16529,11 +16868,11 @@ 200 ], "bodyType": { - "$id": "1047", + "$id": "1071", "kind": "streaming", "name": "SSEStreamSampleEvents", "valueType": { - "$id": "1048", + "$id": "1072", "kind": "union", "name": "SampleEvents", "variantTypes": [ @@ -16583,16 +16922,16 @@ }, "parameters": [ { - "$ref": "1046" + "$ref": "1070" } ], "response": { "type": { - "$id": "1049", + "$id": "1073", "kind": "streaming", "name": "SSEStreamSampleEvents", "valueType": { - "$ref": "1048" + "$ref": "1072" }, "streamKind": "sse", "contentTypes": [ @@ -16608,7 +16947,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.receiveSse" }, { - "$id": "1050", + "$id": "1074", "kind": "basic", "name": "receiveExperimentalJsonLines", "isExactName": false, @@ -16618,14 +16957,14 @@ "2024-08-16-preview" ], "operation": { - "$id": "1051", + "$id": "1075", "name": "receiveExperimentalJsonLines", "isExactName": false, "resourceName": "SampleTypeSpec", "accessibility": "public", "parameters": [ { - "$id": "1052", + "$id": "1076", "kind": "header", "name": "accept", "serializedName": "Accept", @@ -16641,7 +16980,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.receiveExperimentalJsonLines.accept", "methodParameterSegments": [ { - "$id": "1053", + "$id": "1077", "kind": "method", "name": "accept", "serializedName": "Accept", @@ -16668,7 +17007,7 @@ 200 ], "bodyType": { - "$id": "1054", + "$id": "1078", "kind": "streaming", "name": "JsonlStreamPreviewDetails", "valueType": { @@ -16712,12 +17051,12 @@ }, "parameters": [ { - "$ref": "1053" + "$ref": "1077" } ], "response": { "type": { - "$id": "1055", + "$id": "1079", "kind": "streaming", "name": "JsonlStreamPreviewDetails", "valueType": { @@ -16738,12 +17077,12 @@ ], "parameters": [ { - "$id": "1056", + "$id": "1080", "kind": "endpoint", "name": "sampleTypeSpecUrl", "serializedName": "sampleTypeSpecUrl", "type": { - "$id": "1057", + "$id": "1081", "kind": "url", "name": "endpoint", "crossLanguageDefinitionId": "TypeSpec.url" @@ -16759,7 +17098,7 @@ "isExactName": false }, { - "$ref": "954" + "$ref": "978" } ], "initializedBy": 1, @@ -16771,14 +17110,14 @@ ], "children": [ { - "$id": "1058", + "$id": "1082", "kind": "client", "name": "ExperimentalSamples", "isExactName": false, "namespace": "SampleTypeSpec", "methods": [ { - "$id": "1059", + "$id": "1083", "kind": "basic", "name": "read", "isExactName": false, @@ -16788,14 +17127,14 @@ "2024-08-16-preview" ], "operation": { - "$id": "1060", + "$id": "1084", "name": "read", "isExactName": false, "resourceName": "ExperimentalSamples", "accessibility": "public", "parameters": [ { - "$id": "1061", + "$id": "1085", "kind": "header", "name": "accept", "serializedName": "Accept", @@ -16811,7 +17150,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.ExperimentalSamples.read.accept", "methodParameterSegments": [ { - "$id": "1062", + "$id": "1086", "kind": "method", "name": "accept", "serializedName": "Accept", @@ -16864,7 +17203,7 @@ }, "parameters": [ { - "$ref": "1062" + "$ref": "1086" } ], "response": { @@ -16878,7 +17217,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.ExperimentalSamples.read" }, { - "$id": "1063", + "$id": "1087", "kind": "paging", "name": "list", "isExactName": false, @@ -16888,14 +17227,14 @@ "2024-08-16-preview" ], "operation": { - "$id": "1064", + "$id": "1088", "name": "list", "isExactName": false, "resourceName": "ExperimentalSamples", "accessibility": "public", "parameters": [ { - "$id": "1065", + "$id": "1089", "kind": "header", "name": "accept", "serializedName": "Accept", @@ -16911,7 +17250,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.ExperimentalSamples.list.accept", "methodParameterSegments": [ { - "$id": "1066", + "$id": "1090", "kind": "method", "name": "accept", "serializedName": "Accept", @@ -16964,7 +17303,7 @@ }, "parameters": [ { - "$ref": "1066" + "$ref": "1090" } ], "response": { @@ -16989,12 +17328,12 @@ ], "parameters": [ { - "$id": "1067", + "$id": "1091", "kind": "endpoint", "name": "sampleTypeSpecUrl", "serializedName": "sampleTypeSpecUrl", "type": { - "$id": "1068", + "$id": "1092", "kind": "url", "name": "endpoint", "crossLanguageDefinitionId": "TypeSpec.url" @@ -17027,14 +17366,14 @@ } }, { - "$id": "1069", + "$id": "1093", "kind": "client", "name": "AnimalOperations", "isExactName": false, "namespace": "SampleTypeSpec", "methods": [ { - "$id": "1070", + "$id": "1094", "kind": "basic", "name": "updatePetAsAnimal", "isExactName": false, @@ -17045,7 +17384,7 @@ ], "doc": "Update a pet as an animal", "operation": { - "$id": "1071", + "$id": "1095", "name": "updatePetAsAnimal", "isExactName": false, "resourceName": "AnimalOperations", @@ -17053,7 +17392,7 @@ "accessibility": "public", "parameters": [ { - "$id": "1072", + "$id": "1096", "kind": "header", "name": "contentType", "serializedName": "Content-Type", @@ -17070,7 +17409,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.AnimalOperations.updatePetAsAnimal.contentType", "methodParameterSegments": [ { - "$id": "1073", + "$id": "1097", "kind": "method", "name": "contentType", "serializedName": "Content-Type", @@ -17092,7 +17431,7 @@ "isExactName": false }, { - "$id": "1074", + "$id": "1098", "kind": "header", "name": "accept", "serializedName": "Accept", @@ -17108,7 +17447,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.AnimalOperations.updatePetAsAnimal.accept", "methodParameterSegments": [ { - "$id": "1075", + "$id": "1099", "kind": "method", "name": "accept", "serializedName": "Accept", @@ -17129,7 +17468,7 @@ "isExactName": false }, { - "$id": "1076", + "$id": "1100", "kind": "body", "name": "animal", "serializedName": "animal", @@ -17148,7 +17487,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.AnimalOperations.updatePetAsAnimal.animal", "methodParameterSegments": [ { - "$id": "1077", + "$id": "1101", "kind": "method", "name": "animal", "serializedName": "animal", @@ -17209,13 +17548,13 @@ }, "parameters": [ { - "$ref": "1077" + "$ref": "1101" }, { - "$ref": "1073" + "$ref": "1097" }, { - "$ref": "1075" + "$ref": "1099" } ], "response": { @@ -17229,7 +17568,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.AnimalOperations.updatePetAsAnimal" }, { - "$id": "1078", + "$id": "1102", "kind": "basic", "name": "updateDogAsAnimal", "isExactName": false, @@ -17240,7 +17579,7 @@ ], "doc": "Update a dog as an animal", "operation": { - "$id": "1079", + "$id": "1103", "name": "updateDogAsAnimal", "isExactName": false, "resourceName": "AnimalOperations", @@ -17248,7 +17587,7 @@ "accessibility": "public", "parameters": [ { - "$id": "1080", + "$id": "1104", "kind": "header", "name": "contentType", "serializedName": "Content-Type", @@ -17265,7 +17604,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.AnimalOperations.updateDogAsAnimal.contentType", "methodParameterSegments": [ { - "$id": "1081", + "$id": "1105", "kind": "method", "name": "contentType", "serializedName": "Content-Type", @@ -17287,7 +17626,7 @@ "isExactName": false }, { - "$id": "1082", + "$id": "1106", "kind": "header", "name": "accept", "serializedName": "Accept", @@ -17303,7 +17642,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.AnimalOperations.updateDogAsAnimal.accept", "methodParameterSegments": [ { - "$id": "1083", + "$id": "1107", "kind": "method", "name": "accept", "serializedName": "Accept", @@ -17324,7 +17663,7 @@ "isExactName": false }, { - "$id": "1084", + "$id": "1108", "kind": "body", "name": "animal", "serializedName": "animal", @@ -17343,7 +17682,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.AnimalOperations.updateDogAsAnimal.animal", "methodParameterSegments": [ { - "$id": "1085", + "$id": "1109", "kind": "method", "name": "animal", "serializedName": "animal", @@ -17404,13 +17743,13 @@ }, "parameters": [ { - "$ref": "1085" + "$ref": "1109" }, { - "$ref": "1081" + "$ref": "1105" }, { - "$ref": "1083" + "$ref": "1107" } ], "response": { @@ -17426,12 +17765,12 @@ ], "parameters": [ { - "$id": "1086", + "$id": "1110", "kind": "endpoint", "name": "sampleTypeSpecUrl", "serializedName": "sampleTypeSpecUrl", "type": { - "$id": "1087", + "$id": "1111", "kind": "url", "name": "endpoint", "crossLanguageDefinitionId": "TypeSpec.url" @@ -17460,14 +17799,14 @@ "isMultiServiceClient": false }, { - "$id": "1088", + "$id": "1112", "kind": "client", "name": "PetOperations", "isExactName": false, "namespace": "SampleTypeSpec", "methods": [ { - "$id": "1089", + "$id": "1113", "kind": "basic", "name": "updatePetAsPet", "isExactName": false, @@ -17478,7 +17817,7 @@ ], "doc": "Update a pet as a pet", "operation": { - "$id": "1090", + "$id": "1114", "name": "updatePetAsPet", "isExactName": false, "resourceName": "PetOperations", @@ -17486,7 +17825,7 @@ "accessibility": "public", "parameters": [ { - "$id": "1091", + "$id": "1115", "kind": "header", "name": "contentType", "serializedName": "Content-Type", @@ -17503,7 +17842,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.PetOperations.updatePetAsPet.contentType", "methodParameterSegments": [ { - "$id": "1092", + "$id": "1116", "kind": "method", "name": "contentType", "serializedName": "Content-Type", @@ -17525,7 +17864,7 @@ "isExactName": false }, { - "$id": "1093", + "$id": "1117", "kind": "header", "name": "accept", "serializedName": "Accept", @@ -17541,7 +17880,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.PetOperations.updatePetAsPet.accept", "methodParameterSegments": [ { - "$id": "1094", + "$id": "1118", "kind": "method", "name": "accept", "serializedName": "Accept", @@ -17562,7 +17901,7 @@ "isExactName": false }, { - "$id": "1095", + "$id": "1119", "kind": "body", "name": "pet", "serializedName": "pet", @@ -17581,7 +17920,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.PetOperations.updatePetAsPet.pet", "methodParameterSegments": [ { - "$id": "1096", + "$id": "1120", "kind": "method", "name": "pet", "serializedName": "pet", @@ -17642,13 +17981,13 @@ }, "parameters": [ { - "$ref": "1096" + "$ref": "1120" }, { - "$ref": "1092" + "$ref": "1116" }, { - "$ref": "1094" + "$ref": "1118" } ], "response": { @@ -17662,7 +18001,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.PetOperations.updatePetAsPet" }, { - "$id": "1097", + "$id": "1121", "kind": "basic", "name": "updateDogAsPet", "isExactName": false, @@ -17673,7 +18012,7 @@ ], "doc": "Update a dog as a pet", "operation": { - "$id": "1098", + "$id": "1122", "name": "updateDogAsPet", "isExactName": false, "resourceName": "PetOperations", @@ -17681,7 +18020,7 @@ "accessibility": "public", "parameters": [ { - "$id": "1099", + "$id": "1123", "kind": "header", "name": "contentType", "serializedName": "Content-Type", @@ -17698,7 +18037,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.PetOperations.updateDogAsPet.contentType", "methodParameterSegments": [ { - "$id": "1100", + "$id": "1124", "kind": "method", "name": "contentType", "serializedName": "Content-Type", @@ -17720,7 +18059,7 @@ "isExactName": false }, { - "$id": "1101", + "$id": "1125", "kind": "header", "name": "accept", "serializedName": "Accept", @@ -17736,7 +18075,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.PetOperations.updateDogAsPet.accept", "methodParameterSegments": [ { - "$id": "1102", + "$id": "1126", "kind": "method", "name": "accept", "serializedName": "Accept", @@ -17757,7 +18096,7 @@ "isExactName": false }, { - "$id": "1103", + "$id": "1127", "kind": "body", "name": "pet", "serializedName": "pet", @@ -17776,7 +18115,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.PetOperations.updateDogAsPet.pet", "methodParameterSegments": [ { - "$id": "1104", + "$id": "1128", "kind": "method", "name": "pet", "serializedName": "pet", @@ -17837,13 +18176,13 @@ }, "parameters": [ { - "$ref": "1104" + "$ref": "1128" }, { - "$ref": "1100" + "$ref": "1124" }, { - "$ref": "1102" + "$ref": "1126" } ], "response": { @@ -17859,12 +18198,12 @@ ], "parameters": [ { - "$id": "1105", + "$id": "1129", "kind": "endpoint", "name": "sampleTypeSpecUrl", "serializedName": "sampleTypeSpecUrl", "type": { - "$id": "1106", + "$id": "1130", "kind": "url", "name": "endpoint", "crossLanguageDefinitionId": "TypeSpec.url" @@ -17893,14 +18232,14 @@ "isMultiServiceClient": false }, { - "$id": "1107", + "$id": "1131", "kind": "client", "name": "DogOperations", "isExactName": false, "namespace": "SampleTypeSpec", "methods": [ { - "$id": "1108", + "$id": "1132", "kind": "basic", "name": "updateDogAsDog", "isExactName": false, @@ -17911,7 +18250,7 @@ ], "doc": "Update a dog as a dog", "operation": { - "$id": "1109", + "$id": "1133", "name": "updateDogAsDog", "isExactName": false, "resourceName": "DogOperations", @@ -17919,7 +18258,7 @@ "accessibility": "public", "parameters": [ { - "$id": "1110", + "$id": "1134", "kind": "header", "name": "contentType", "serializedName": "Content-Type", @@ -17936,7 +18275,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.DogOperations.updateDogAsDog.contentType", "methodParameterSegments": [ { - "$id": "1111", + "$id": "1135", "kind": "method", "name": "contentType", "serializedName": "Content-Type", @@ -17958,7 +18297,7 @@ "isExactName": false }, { - "$id": "1112", + "$id": "1136", "kind": "header", "name": "accept", "serializedName": "Accept", @@ -17974,7 +18313,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.DogOperations.updateDogAsDog.accept", "methodParameterSegments": [ { - "$id": "1113", + "$id": "1137", "kind": "method", "name": "accept", "serializedName": "Accept", @@ -17995,7 +18334,7 @@ "isExactName": false }, { - "$id": "1114", + "$id": "1138", "kind": "body", "name": "dog", "serializedName": "dog", @@ -18014,7 +18353,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.DogOperations.updateDogAsDog.dog", "methodParameterSegments": [ { - "$id": "1115", + "$id": "1139", "kind": "method", "name": "dog", "serializedName": "dog", @@ -18075,13 +18414,13 @@ }, "parameters": [ { - "$ref": "1115" + "$ref": "1139" }, { - "$ref": "1111" + "$ref": "1135" }, { - "$ref": "1113" + "$ref": "1137" } ], "response": { @@ -18097,12 +18436,12 @@ ], "parameters": [ { - "$id": "1116", + "$id": "1140", "kind": "endpoint", "name": "sampleTypeSpecUrl", "serializedName": "sampleTypeSpecUrl", "type": { - "$id": "1117", + "$id": "1141", "kind": "url", "name": "endpoint", "crossLanguageDefinitionId": "TypeSpec.url" @@ -18131,14 +18470,14 @@ "isMultiServiceClient": false }, { - "$id": "1118", + "$id": "1142", "kind": "client", "name": "PlantOperations", "isExactName": false, "namespace": "SampleTypeSpec", "methods": [ { - "$id": "1119", + "$id": "1143", "kind": "basic", "name": "getTree", "isExactName": false, @@ -18149,7 +18488,7 @@ ], "doc": "Get a tree as a plant", "operation": { - "$id": "1120", + "$id": "1144", "name": "getTree", "isExactName": false, "resourceName": "PlantOperations", @@ -18157,7 +18496,7 @@ "accessibility": "public", "parameters": [ { - "$id": "1121", + "$id": "1145", "kind": "header", "name": "accept", "serializedName": "Accept", @@ -18173,7 +18512,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.PlantOperations.getTree.accept", "methodParameterSegments": [ { - "$id": "1122", + "$id": "1146", "kind": "method", "name": "accept", "serializedName": "Accept", @@ -18234,7 +18573,7 @@ }, "parameters": [ { - "$ref": "1122" + "$ref": "1146" } ], "response": { @@ -18248,7 +18587,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.PlantOperations.getTree" }, { - "$id": "1123", + "$id": "1147", "kind": "basic", "name": "getTreeAsJson", "isExactName": false, @@ -18259,7 +18598,7 @@ ], "doc": "Get a tree as a plant", "operation": { - "$id": "1124", + "$id": "1148", "name": "getTreeAsJson", "isExactName": false, "resourceName": "PlantOperations", @@ -18267,7 +18606,7 @@ "accessibility": "public", "parameters": [ { - "$id": "1125", + "$id": "1149", "kind": "header", "name": "accept", "serializedName": "Accept", @@ -18283,7 +18622,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.PlantOperations.getTreeAsJson.accept", "methodParameterSegments": [ { - "$id": "1126", + "$id": "1150", "kind": "method", "name": "accept", "serializedName": "Accept", @@ -18344,7 +18683,7 @@ }, "parameters": [ { - "$ref": "1126" + "$ref": "1150" } ], "response": { @@ -18358,7 +18697,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.PlantOperations.getTreeAsJson" }, { - "$id": "1127", + "$id": "1151", "kind": "basic", "name": "updateTree", "isExactName": false, @@ -18369,7 +18708,7 @@ ], "doc": "Update a tree as a plant", "operation": { - "$id": "1128", + "$id": "1152", "name": "updateTree", "isExactName": false, "resourceName": "PlantOperations", @@ -18377,7 +18716,7 @@ "accessibility": "public", "parameters": [ { - "$id": "1129", + "$id": "1153", "kind": "header", "name": "contentType", "serializedName": "Content-Type", @@ -18393,7 +18732,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.PlantOperations.updateTree.contentType", "methodParameterSegments": [ { - "$id": "1130", + "$id": "1154", "kind": "method", "name": "contentType", "serializedName": "Content-Type", @@ -18414,7 +18753,7 @@ "isExactName": false }, { - "$id": "1131", + "$id": "1155", "kind": "header", "name": "accept", "serializedName": "Accept", @@ -18430,7 +18769,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.PlantOperations.updateTree.accept", "methodParameterSegments": [ { - "$id": "1132", + "$id": "1156", "kind": "method", "name": "accept", "serializedName": "Accept", @@ -18451,7 +18790,7 @@ "isExactName": false }, { - "$id": "1133", + "$id": "1157", "kind": "body", "name": "tree", "serializedName": "tree", @@ -18470,7 +18809,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.PlantOperations.updateTree.tree", "methodParameterSegments": [ { - "$id": "1134", + "$id": "1158", "kind": "method", "name": "tree", "serializedName": "tree", @@ -18539,13 +18878,13 @@ }, "parameters": [ { - "$ref": "1134" + "$ref": "1158" }, { - "$ref": "1130" + "$ref": "1154" }, { - "$ref": "1132" + "$ref": "1156" } ], "response": { @@ -18559,7 +18898,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.PlantOperations.updateTree" }, { - "$id": "1135", + "$id": "1159", "kind": "basic", "name": "updateTreeAsJson", "isExactName": false, @@ -18570,7 +18909,7 @@ ], "doc": "Update a tree as a plant", "operation": { - "$id": "1136", + "$id": "1160", "name": "updateTreeAsJson", "isExactName": false, "resourceName": "PlantOperations", @@ -18578,7 +18917,7 @@ "accessibility": "public", "parameters": [ { - "$id": "1137", + "$id": "1161", "kind": "header", "name": "contentType", "serializedName": "Content-Type", @@ -18594,7 +18933,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.PlantOperations.updateTreeAsJson.contentType", "methodParameterSegments": [ { - "$id": "1138", + "$id": "1162", "kind": "method", "name": "contentType", "serializedName": "Content-Type", @@ -18615,7 +18954,7 @@ "isExactName": false }, { - "$id": "1139", + "$id": "1163", "kind": "header", "name": "accept", "serializedName": "Accept", @@ -18631,7 +18970,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.PlantOperations.updateTreeAsJson.accept", "methodParameterSegments": [ { - "$id": "1140", + "$id": "1164", "kind": "method", "name": "accept", "serializedName": "Accept", @@ -18652,7 +18991,7 @@ "isExactName": false }, { - "$id": "1141", + "$id": "1165", "kind": "body", "name": "tree", "serializedName": "tree", @@ -18671,7 +19010,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.PlantOperations.updateTreeAsJson.tree", "methodParameterSegments": [ { - "$id": "1142", + "$id": "1166", "kind": "method", "name": "tree", "serializedName": "tree", @@ -18740,13 +19079,13 @@ }, "parameters": [ { - "$ref": "1142" + "$ref": "1166" }, { - "$ref": "1138" + "$ref": "1162" }, { - "$ref": "1140" + "$ref": "1164" } ], "response": { @@ -18762,12 +19101,12 @@ ], "parameters": [ { - "$id": "1143", + "$id": "1167", "kind": "endpoint", "name": "sampleTypeSpecUrl", "serializedName": "sampleTypeSpecUrl", "type": { - "$id": "1144", + "$id": "1168", "kind": "url", "name": "endpoint", "crossLanguageDefinitionId": "TypeSpec.url" @@ -18796,14 +19135,14 @@ "isMultiServiceClient": false }, { - "$id": "1145", + "$id": "1169", "kind": "client", "name": "Metrics", "isExactName": false, "namespace": "SampleTypeSpec", "methods": [ { - "$id": "1146", + "$id": "1170", "kind": "basic", "name": "getWidgetMetrics", "isExactName": false, @@ -18814,7 +19153,7 @@ ], "doc": "Get Widget metrics for given day of week", "operation": { - "$id": "1147", + "$id": "1171", "name": "getWidgetMetrics", "isExactName": false, "resourceName": "Metrics", @@ -18822,12 +19161,12 @@ "accessibility": "public", "parameters": [ { - "$id": "1148", + "$id": "1172", "kind": "path", "name": "metricsNamespace", "serializedName": "metricsNamespace", "type": { - "$id": "1149", + "$id": "1173", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -18845,12 +19184,12 @@ "crossLanguageDefinitionId": "SampleTypeSpec.Metrics.getWidgetMetrics.metricsNamespace", "methodParameterSegments": [ { - "$id": "1150", + "$id": "1174", "kind": "method", "name": "metricsNamespace", "serializedName": "metricsNamespace", "type": { - "$id": "1151", + "$id": "1175", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -18870,7 +19209,7 @@ "isExactName": false }, { - "$id": "1152", + "$id": "1176", "kind": "path", "name": "day", "serializedName": "day", @@ -18889,7 +19228,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.Metrics.getWidgetMetrics.day", "methodParameterSegments": [ { - "$id": "1153", + "$id": "1177", "kind": "method", "name": "day", "serializedName": "day", @@ -18910,7 +19249,7 @@ "isExactName": false }, { - "$id": "1154", + "$id": "1178", "kind": "header", "name": "accept", "serializedName": "Accept", @@ -18926,7 +19265,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.Metrics.getWidgetMetrics.accept", "methodParameterSegments": [ { - "$id": "1155", + "$id": "1179", "kind": "method", "name": "accept", "serializedName": "Accept", @@ -18979,10 +19318,10 @@ }, "parameters": [ { - "$ref": "1153" + "$ref": "1177" }, { - "$ref": "1155" + "$ref": "1179" } ], "response": { @@ -18998,12 +19337,12 @@ ], "parameters": [ { - "$id": "1156", + "$id": "1180", "kind": "endpoint", "name": "sampleTypeSpecUrl", "serializedName": "sampleTypeSpecUrl", "type": { - "$id": "1157", + "$id": "1181", "kind": "url", "name": "endpoint", "crossLanguageDefinitionId": "TypeSpec.url" @@ -19019,7 +19358,7 @@ "isExactName": false }, { - "$ref": "1150" + "$ref": "1174" } ], "initializedBy": 3, @@ -19035,14 +19374,14 @@ "isMultiServiceClient": false }, { - "$id": "1158", + "$id": "1182", "kind": "client", "name": "Notebooks", "isExactName": false, "namespace": "SampleTypeSpec", "methods": [ { - "$id": "1159", + "$id": "1183", "kind": "basic", "name": "getNotebook", "isExactName": false, @@ -19053,7 +19392,7 @@ ], "doc": "Get a notebook by name", "operation": { - "$id": "1160", + "$id": "1184", "name": "getNotebook", "isExactName": false, "resourceName": "Notebooks", @@ -19061,12 +19400,12 @@ "accessibility": "public", "parameters": [ { - "$id": "1161", + "$id": "1185", "kind": "path", "name": "notebookName", "serializedName": "notebookName", "type": { - "$id": "1162", + "$id": "1186", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -19084,12 +19423,12 @@ "crossLanguageDefinitionId": "SampleTypeSpec.Notebooks.getNotebook.notebookName", "methodParameterSegments": [ { - "$id": "1163", + "$id": "1187", "kind": "method", "name": "notebook", "serializedName": "notebook", "type": { - "$id": "1164", + "$id": "1188", "kind": "string", "name": "string", "crossLanguageDefinitionId": "TypeSpec.string", @@ -19110,7 +19449,7 @@ "isExactName": false }, { - "$id": "1165", + "$id": "1189", "kind": "header", "name": "accept", "serializedName": "Accept", @@ -19126,7 +19465,7 @@ "crossLanguageDefinitionId": "SampleTypeSpec.Notebooks.getNotebook.accept", "methodParameterSegments": [ { - "$id": "1166", + "$id": "1190", "kind": "method", "name": "accept", "serializedName": "Accept", @@ -19179,7 +19518,7 @@ }, "parameters": [ { - "$ref": "1166" + "$ref": "1190" } ], "response": { @@ -19195,12 +19534,12 @@ ], "parameters": [ { - "$id": "1167", + "$id": "1191", "kind": "endpoint", "name": "sampleTypeSpecUrl", "serializedName": "sampleTypeSpecUrl", "type": { - "$id": "1168", + "$id": "1192", "kind": "url", "name": "endpoint", "crossLanguageDefinitionId": "TypeSpec.url" @@ -19216,7 +19555,7 @@ "isExactName": false }, { - "$ref": "1163" + "$ref": "1187" } ], "initializedBy": 3,