@azure-tools/typespec-ts 0.48.0 → 0.48.1-alpha.20260127.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/src/index.d.ts.map +1 -1
  3. package/dist/src/index.js +20 -5
  4. package/dist/src/index.js.map +1 -1
  5. package/dist/src/modular/buildClientContext.d.ts.map +1 -1
  6. package/dist/src/modular/buildClientContext.js +7 -3
  7. package/dist/src/modular/buildClientContext.js.map +1 -1
  8. package/dist/src/modular/buildOperations.d.ts.map +1 -1
  9. package/dist/src/modular/buildOperations.js +24 -3
  10. package/dist/src/modular/buildOperations.js.map +1 -1
  11. package/dist/src/modular/emitModels.d.ts.map +1 -1
  12. package/dist/src/modular/emitModels.js +19 -0
  13. package/dist/src/modular/emitModels.js.map +1 -1
  14. package/dist/src/modular/emitSamples.js +2 -2
  15. package/dist/src/modular/emitSamples.js.map +1 -1
  16. package/dist/src/modular/helpers/clientHelpers.d.ts +2 -1
  17. package/dist/src/modular/helpers/clientHelpers.d.ts.map +1 -1
  18. package/dist/src/modular/helpers/clientHelpers.js +5 -2
  19. package/dist/src/modular/helpers/clientHelpers.js.map +1 -1
  20. package/dist/src/modular/helpers/operationHelpers.d.ts.map +1 -1
  21. package/dist/src/modular/helpers/operationHelpers.js +266 -43
  22. package/dist/src/modular/helpers/operationHelpers.js.map +1 -1
  23. package/dist/src/modular/serialization/buildXmlSerializerFunction.d.ts +32 -0
  24. package/dist/src/modular/serialization/buildXmlSerializerFunction.d.ts.map +1 -0
  25. package/dist/src/modular/serialization/buildXmlSerializerFunction.js +373 -0
  26. package/dist/src/modular/serialization/buildXmlSerializerFunction.js.map +1 -0
  27. package/dist/src/modular/static-helpers-metadata.d.ts +57 -0
  28. package/dist/src/modular/static-helpers-metadata.d.ts.map +1 -1
  29. package/dist/src/modular/static-helpers-metadata.js +57 -0
  30. package/dist/src/modular/static-helpers-metadata.js.map +1 -1
  31. package/dist/src/utils/clientUtils.d.ts.map +1 -1
  32. package/dist/src/utils/clientUtils.js +1 -0
  33. package/dist/src/utils/clientUtils.js.map +1 -1
  34. package/dist/src/utils/mediaTypes.d.ts +4 -0
  35. package/dist/src/utils/mediaTypes.d.ts.map +1 -1
  36. package/dist/src/utils/mediaTypes.js +10 -0
  37. package/dist/src/utils/mediaTypes.js.map +1 -1
  38. package/dist/src/utils/modelUtils.d.ts.map +1 -1
  39. package/dist/src/utils/modelUtils.js +3 -0
  40. package/dist/src/utils/modelUtils.js.map +1 -1
  41. package/dist/src/utils/operationUtil.d.ts +12 -0
  42. package/dist/src/utils/operationUtil.d.ts.map +1 -1
  43. package/dist/src/utils/operationUtil.js +22 -1
  44. package/dist/src/utils/operationUtil.js.map +1 -1
  45. package/dist/tsconfig.tsbuildinfo +1 -1
  46. package/package.json +8 -7
  47. package/src/index.ts +20 -5
  48. package/src/modular/buildClientContext.ts +12 -5
  49. package/src/modular/buildOperations.ts +34 -3
  50. package/src/modular/emitModels.ts +43 -0
  51. package/src/modular/emitSamples.ts +2 -2
  52. package/src/modular/helpers/clientHelpers.ts +6 -2
  53. package/src/modular/helpers/operationHelpers.ts +377 -57
  54. package/src/modular/serialization/buildXmlSerializerFunction.ts +511 -0
  55. package/src/modular/static-helpers-metadata.ts +58 -0
  56. package/src/utils/clientUtils.ts +1 -0
  57. package/src/utils/mediaTypes.ts +12 -0
  58. package/src/utils/modelUtils.ts +3 -0
  59. package/src/utils/operationUtil.ts +34 -1
  60. package/static/static-helpers/serialization/xml-helpers.ts +596 -0
@@ -9,7 +9,8 @@ import {
9
9
  PagingHelpers,
10
10
  PollingHelpers,
11
11
  SerializationHelpers,
12
- UrlTemplateHelpers
12
+ UrlTemplateHelpers,
13
+ XmlHelpers
13
14
  } from "../static-helpers-metadata.js";
14
15
  import {
15
16
  getNullableValidType,
@@ -21,6 +22,9 @@ import {
21
22
  getCollectionFormatHelper,
22
23
  hasCollectionFormatInfo,
23
24
  isBinaryPayload,
25
+ isXmlPayload,
26
+ isMultipartPayload,
27
+ hasDualFormatSupport,
24
28
  ServiceOperation,
25
29
  getCollectionFormatParseHelper,
26
30
  getCollectionFormatFromArrayEncoding,
@@ -46,6 +50,11 @@ import {
46
50
  buildModelSerializer,
47
51
  buildPropertySerializer
48
52
  } from "../serialization/buildSerializerFunction.js";
53
+ import {
54
+ buildXmlModelSerializer,
55
+ buildXmlModelDeserializer,
56
+ hasXmlSerialization
57
+ } from "../serialization/buildXmlSerializerFunction.js";
49
58
  import { refkey } from "../../framework/refkey.js";
50
59
  import { reportDiagnostic } from "../../lib.js";
51
60
  import { resolveReference } from "../../framework/reference.js";
@@ -63,6 +72,7 @@ import {
63
72
  SdkBodyParameter,
64
73
  SdkClientType,
65
74
  SdkConstantType,
75
+ SdkEnumType,
66
76
  SdkHttpOperation,
67
77
  SdkHttpParameter,
68
78
  SdkLroPagingServiceMethod,
@@ -76,6 +86,7 @@ import {
76
86
  } from "@azure-tools/typespec-client-generator-core";
77
87
  import { isMetadata } from "@typespec/http";
78
88
  import { useContext } from "../../contextManager.js";
89
+ import { isExtensibleEnum } from "../type-expressions/get-enum-expression.js";
79
90
 
80
91
  export function getSendPrivateFunction(
81
92
  dpgContext: SdkContext,
@@ -158,16 +169,15 @@ export function getDeserializePrivateFunction(
158
169
  type: PathUncheckedResponseReference
159
170
  }
160
171
  ];
161
- // TODO: Support LRO + paging operation
162
- // https://github.com/Azure/autorest.typescript/issues/2313
163
172
  const isLroOnly = isLroOnlyOperation(operation);
173
+ const isLroAndPaging = isLroAndPagingOperation(operation);
164
174
 
165
175
  // TODO: Support operation overloads
166
176
  // TODO: Support multiple responses
167
177
  const response = operation.response;
168
178
  const restResponse = operation.operation.responses[0];
169
179
  let returnType;
170
- if (isLroOnly) {
180
+ if (isLroOnly || isLroAndPaging) {
171
181
  returnType = buildLroReturnType(context, operation);
172
182
  } else if (response.type && restResponse) {
173
183
  returnType = {
@@ -198,11 +208,12 @@ export function getDeserializePrivateFunction(
198
208
  `${getExceptionThrowStatement(context, operation)}`,
199
209
  "}"
200
210
  );
201
- const deserializedType = isLroOnly
202
- ? operation?.lroMetadata?.finalResponse?.result
203
- : restResponse
204
- ? restResponse.type
205
- : response.type;
211
+ const deserializedType =
212
+ isLroOnly || isLroAndPaging
213
+ ? operation?.lroMetadata?.finalResponse?.result
214
+ : restResponse
215
+ ? restResponse.type
216
+ : response.type;
206
217
  const lroSubSegments = isLroOnly
207
218
  ? operation?.lroMetadata?.finalResponse?.resultSegments
208
219
  : undefined;
@@ -229,31 +240,130 @@ export function getDeserializePrivateFunction(
229
240
  }
230
241
 
231
242
  if (deserializedType) {
232
- const contentTypes = operation.operation.responses[0]?.contentTypes;
233
- const deserializeFunctionName = buildModelDeserializer(
234
- context,
235
- deserializedType,
236
- {
237
- nameOnly: true,
238
- skipDiscriminatedUnionSuffix: false
243
+ const contentTypes = operation.operation.responses[0]?.contentTypes ?? [];
244
+ const isXml = isXmlPayload(contentTypes);
245
+ const isDualFormat = hasDualFormatSupport(contentTypes);
246
+ const isMultipart = isMultipartPayload(contentTypes);
247
+ const useXmlDeserialization =
248
+ isXml &&
249
+ deserializedType.kind === "model" &&
250
+ hasXmlSerialization(deserializedType);
251
+
252
+ // Workaround for multipart response: cast return value as any due to lack of multipart response handling in core
253
+ const multipartCastSuffix = isMultipart ? " as any" : "";
254
+
255
+ // For dual-format responses, check content-type header at runtime
256
+ if (
257
+ isDualFormat &&
258
+ deserializedType.kind === "model" &&
259
+ hasXmlSerialization(deserializedType)
260
+ ) {
261
+ const xmlDeserializerName = buildXmlModelDeserializer(
262
+ context,
263
+ deserializedType,
264
+ {
265
+ nameOnly: true,
266
+ skipDiscriminatedUnionSuffix: false
267
+ }
268
+ ) as string | undefined;
269
+ const jsonDeserializerName = buildModelDeserializer(
270
+ context,
271
+ deserializedType,
272
+ {
273
+ nameOnly: true,
274
+ skipDiscriminatedUnionSuffix: false
275
+ }
276
+ );
277
+
278
+ if (xmlDeserializerName && jsonDeserializerName) {
279
+ const isXmlContentTypeRef = resolveReference(
280
+ XmlHelpers.isXmlContentType
281
+ );
282
+ statements.push(
283
+ `const responseContentType = result.headers?.["content-type"] ?? "";
284
+ if (${isXmlContentTypeRef}(responseContentType)) {
285
+ return ${xmlDeserializerName}(${deserializedRoot});
286
+ }
287
+ return ${jsonDeserializerName}(${deserializedRoot});`
288
+ );
289
+ } else {
290
+ // Fall back to JSON deserializer
291
+ const deserializeFunctionName = buildModelDeserializer(
292
+ context,
293
+ deserializedType,
294
+ {
295
+ nameOnly: true,
296
+ skipDiscriminatedUnionSuffix: false
297
+ }
298
+ );
299
+ if (deserializeFunctionName) {
300
+ statements.push(
301
+ `return ${deserializeFunctionName}(${deserializedRoot})`
302
+ );
303
+ }
239
304
  }
240
- );
241
- if (deserializeFunctionName) {
242
- statements.push(`return ${deserializeFunctionName}(${deserializedRoot})`);
243
- } else if (isAzureCoreErrorType(context.program, deserializedType.__raw)) {
244
- statements.push(`return ${deserializedRoot}`);
245
- } else {
246
- statements.push(
247
- `return ${deserializeResponseValue(
305
+ } else if (useXmlDeserialization) {
306
+ // XML-only response
307
+ const xmlDeserializerName = buildXmlModelDeserializer(
308
+ context,
309
+ deserializedType,
310
+ {
311
+ nameOnly: true,
312
+ skipDiscriminatedUnionSuffix: false
313
+ }
314
+ ) as string | undefined;
315
+
316
+ if (xmlDeserializerName) {
317
+ statements.push(`return ${xmlDeserializerName}(${deserializedRoot})`);
318
+ } else {
319
+ // Fall back to JSON deserializer if XML deserializer is not available
320
+ const deserializeFunctionName = buildModelDeserializer(
248
321
  context,
249
322
  deserializedType,
250
- deserializedRoot,
251
- true,
252
- isBinaryPayload(context, response.type!.__raw!, contentTypes!)
253
- ? "binary"
254
- : getEncodeForType(deserializedType)
255
- )}`
323
+ {
324
+ nameOnly: true,
325
+ skipDiscriminatedUnionSuffix: false
326
+ }
327
+ );
328
+ if (deserializeFunctionName) {
329
+ statements.push(
330
+ `return ${deserializeFunctionName}(${deserializedRoot})`
331
+ );
332
+ } else {
333
+ statements.push(`return ${deserializedRoot}`);
334
+ }
335
+ }
336
+ } else {
337
+ // JSON response (default) - also handles multipart responses
338
+ const deserializeFunctionName = buildModelDeserializer(
339
+ context,
340
+ deserializedType,
341
+ {
342
+ nameOnly: true,
343
+ skipDiscriminatedUnionSuffix: false
344
+ }
256
345
  );
346
+ if (deserializeFunctionName) {
347
+ statements.push(
348
+ `return ${deserializeFunctionName}(${deserializedRoot})${multipartCastSuffix}`
349
+ );
350
+ } else if (
351
+ isAzureCoreErrorType(context.program, deserializedType.__raw)
352
+ ) {
353
+ statements.push(`return ${deserializedRoot}${multipartCastSuffix}`);
354
+ } else {
355
+ statements.push(
356
+ `return ${deserializeResponseValue(
357
+ context,
358
+ deserializedType,
359
+ deserializedRoot,
360
+ true,
361
+ isBinaryPayload(context, response.type!.__raw!, contentTypes)
362
+ ? "binary"
363
+ : getEncodeForType(deserializedType)
364
+ )}${multipartCastSuffix}`
365
+ );
366
+ }
257
367
  }
258
368
  } else if (returnType.type === "void") {
259
369
  statements.push("return;");
@@ -465,8 +575,13 @@ export function getOperationFunction(
465
575
  optionalParamName
466
576
  );
467
577
  } else if (isLroAndPagingOperation(operation)) {
468
- // Case 3: both paging + lro operation is not supported yet so handle them as normal operation and customization may be needed
469
- // https://github.com/Azure/autorest.typescript/issues/2313
578
+ // Case 3: both paging + lro operation
579
+ return getLroAndPagingOperationFunction(
580
+ context,
581
+ [method[0], operation],
582
+ clientType,
583
+ optionalParamName
584
+ );
470
585
  }
471
586
 
472
587
  // TODO: Support operation overloads
@@ -594,9 +709,99 @@ function getLroOnlyOperationFunction(
594
709
  } as FunctionDeclarationStructure & { propertyName?: string };
595
710
  }
596
711
 
712
+ function getLroAndPagingOperationFunction(
713
+ context: SdkContext,
714
+ method: [string[], SdkLroPagingServiceMethod<SdkHttpOperation>],
715
+ clientType: string,
716
+ optionalParamName: string = "options"
717
+ ): FunctionDeclarationStructure & { propertyName?: string } {
718
+ const operation = method[1];
719
+ const parameters = getOperationSignatureParameters(
720
+ context,
721
+ method,
722
+ clientType
723
+ );
724
+ const { name, fixme = [] } = getOperationName(operation);
725
+
726
+ const returnType = buildLroPagingReturnType(context, operation);
727
+
728
+ // Build paging options from metadata
729
+ const pagingOptions = [
730
+ operation.response.resultSegments &&
731
+ `itemName: "${operation.response.resultSegments.map((p) => p.name).join(".")}"`,
732
+ operation.pagingMetadata.nextLinkSegments &&
733
+ `nextLinkName: "${operation.pagingMetadata.nextLinkSegments.map((p) => p.name).join(".")}"`,
734
+ operation.pagingMetadata.nextLinkVerb !== "GET" &&
735
+ `nextLinkMethod: "${operation.pagingMetadata.nextLinkVerb}"`
736
+ ].filter(Boolean);
737
+
738
+ // Build LRO resource location config
739
+ const allowedLocations = [
740
+ "azure-async-operation",
741
+ "location",
742
+ "original-uri",
743
+ "operation-location"
744
+ ];
745
+ const resourceLocationConfig =
746
+ operation.lroMetadata?.finalStateVia &&
747
+ allowedLocations.includes(operation.lroMetadata.finalStateVia)
748
+ ? `resourceLocationConfig: "${operation.lroMetadata.finalStateVia}"`
749
+ : "";
750
+
751
+ // Resolve references
752
+ const refs = {
753
+ pagedIterator: resolveReference(PagingHelpers.PagedAsyncIterableIterator),
754
+ buildPaging: resolveReference(PagingHelpers.BuildPagedAsyncIterator),
755
+ getLroPoller: resolveReference(PollingHelpers.GetLongRunningPoller),
756
+ pollerLike: resolveReference(AzurePollingDependencies.PollerLike),
757
+ operationState: resolveReference(AzurePollingDependencies.OperationState),
758
+ pathResponse: resolveReference(useDependencies().PathUncheckedResponse)
759
+ };
760
+
761
+ const expectedStatuses = getExpectedStatuses(operation);
762
+ const paramList = parameters.map((p) => p.name).join(", ");
763
+ const pagingOptionsStr =
764
+ pagingOptions.length > 0 ? `,\n {${pagingOptions.join(", ")}}` : "";
765
+
766
+ return {
767
+ kind: StructureKind.Function,
768
+ docs: [
769
+ ...getDocsFromDescription(operation.doc),
770
+ ...getFixmeForMultilineDocs(fixme)
771
+ ],
772
+ isAsync: false,
773
+ isExported: true,
774
+ name,
775
+ propertyName: normalizeName(operation.name, NameType.Property),
776
+ parameters,
777
+ returnType: `${refs.pagedIterator}<${returnType.type}>`,
778
+ statements: [
779
+ `
780
+ const initialPagingPoller = ${refs.getLroPoller}(context,
781
+ async (result: ${refs.pathResponse}) => result,
782
+ ${expectedStatuses}, {
783
+ updateIntervalInMs: ${optionalParamName}?.updateIntervalInMs,
784
+ abortSignal: ${optionalParamName}?.abortSignal,
785
+ getInitialResponse: () => _${name}Send(${paramList}),
786
+ ${resourceLocationConfig}
787
+ }) as ${refs.pollerLike}<${refs.operationState}<${refs.pathResponse}>, ${refs.pathResponse}>;
788
+
789
+ return ${refs.buildPaging}(
790
+ context,
791
+ async () => await initialPagingPoller,
792
+ _${name}Deserialize,
793
+ ${expectedStatuses}${pagingOptionsStr}
794
+ );
795
+ `
796
+ ]
797
+ };
798
+ }
799
+
597
800
  function buildLroReturnType(
598
801
  context: SdkContext,
599
- operation: SdkLroServiceMethod<SdkHttpOperation>
802
+ operation:
803
+ | SdkLroServiceMethod<SdkHttpOperation>
804
+ | SdkLroPagingServiceMethod<SdkHttpOperation>
600
805
  ) {
601
806
  const metadata = operation.lroMetadata;
602
807
  if (metadata !== undefined && metadata.finalResponse !== undefined) {
@@ -609,6 +814,19 @@ function buildLroReturnType(
609
814
  return { name: "", type: "void" };
610
815
  }
611
816
 
817
+ function buildLroPagingReturnType(
818
+ context: SdkContext,
819
+ operation: SdkLroPagingServiceMethod<SdkHttpOperation>
820
+ ) {
821
+ if (operation.response.type?.kind === "array") {
822
+ return {
823
+ name: (operation.response.type.valueType as any).name ?? "",
824
+ type: getTypeExpression(context, operation.response.type.valueType)
825
+ };
826
+ }
827
+ return { name: "", type: "void" };
828
+ }
829
+
612
830
  function getPagingOnlyOperationFunction(
613
831
  context: SdkContext,
614
832
  method: [string[], SdkPagingServiceMethod<SdkHttpOperation>],
@@ -824,14 +1042,31 @@ function buildBodyParameter(
824
1042
  if (!bodyParameter || !bodyParameter.type) {
825
1043
  return "";
826
1044
  }
827
- const serializerFunctionName = buildModelSerializer(
828
- context,
829
- getNullableValidType(bodyParameter.type),
830
- {
1045
+
1046
+ const contentTypes = bodyParameter.contentTypes;
1047
+ const isXml = isXmlPayload(contentTypes);
1048
+ const isDualFormat = hasDualFormatSupport(contentTypes);
1049
+ const bodyType = getNullableValidType(bodyParameter.type);
1050
+
1051
+ // Check if XML serialization is needed and available
1052
+ const useXmlSerialization =
1053
+ isXml && bodyType.kind === "model" && hasXmlSerialization(bodyType);
1054
+
1055
+ let serializerFunctionName: string | undefined;
1056
+
1057
+ if (useXmlSerialization) {
1058
+ // Use XML serializer
1059
+ serializerFunctionName = buildXmlModelSerializer(context, bodyType, {
831
1060
  nameOnly: true,
832
1061
  skipDiscriminatedUnionSuffix: false
833
- }
834
- );
1062
+ }) as string | undefined;
1063
+ } else {
1064
+ // Use JSON serializer (default)
1065
+ serializerFunctionName = buildModelSerializer(context, bodyType, {
1066
+ nameOnly: true,
1067
+ skipDiscriminatedUnionSuffix: false
1068
+ }) as string | undefined;
1069
+ }
835
1070
 
836
1071
  const bodyParamName = normalizeName(
837
1072
  bodyParameter.name,
@@ -846,6 +1081,28 @@ function buildBodyParameter(
846
1081
  bodyParameter,
847
1082
  bodyParameter.optional ? optionalParamName : undefined
848
1083
  );
1084
+
1085
+ // For dual-format operations, check the contentType option at runtime
1086
+ if (
1087
+ isDualFormat &&
1088
+ bodyType.kind === "model" &&
1089
+ hasXmlSerialization(bodyType)
1090
+ ) {
1091
+ const xmlSerializerName = buildXmlModelSerializer(context, bodyType, {
1092
+ nameOnly: true,
1093
+ skipDiscriminatedUnionSuffix: false
1094
+ }) as string | undefined;
1095
+ const jsonSerializerName = buildModelSerializer(context, bodyType, {
1096
+ nameOnly: true,
1097
+ skipDiscriminatedUnionSuffix: false
1098
+ }) as string | undefined;
1099
+
1100
+ if (xmlSerializerName && jsonSerializerName) {
1101
+ const isXmlContentTypeRef = resolveReference(XmlHelpers.isXmlContentType);
1102
+ return `\nbody: ${nullOrUndefinedPrefix}(${isXmlContentTypeRef}(${optionalParamName}?.contentType ?? "application/json") ? ${xmlSerializerName}(${bodyNameExpression}) : ${jsonSerializerName}(${bodyNameExpression})),`;
1103
+ }
1104
+ }
1105
+
849
1106
  // if a model being used in both spread and non spread operation, we should only leverage the deserializer in non spread operation
850
1107
  if (serializerFunctionName && !isSpreadBodyParameter(bodyParameter)) {
851
1108
  return `\nbody: ${nullOrUndefinedPrefix}${serializerFunctionName}(${bodyNameExpression}),`;
@@ -884,21 +1141,32 @@ export function getParameterMap(
884
1141
  param: SdkHttpParameter,
885
1142
  optionalParamName: string = "options"
886
1143
  ): string {
1144
+ // Use lowercase for header names since HTTP headers are case-insensitive
1145
+ const serializedName =
1146
+ param.kind === "header"
1147
+ ? getHeaderSerializedName(param)
1148
+ : getPropertySerializedName(param);
1149
+
887
1150
  if (isConstant(param.type)) {
888
- return `"${param.name}": ${getConstantValue(param.type)}`;
1151
+ return `"${serializedName}": ${getConstantValue(param.type)}`;
889
1152
  }
890
1153
 
891
1154
  if (hasCollectionFormatInfo(param.kind, (param as any).collectionFormat)) {
892
- return getCollectionFormatForParam(context, param, optionalParamName);
1155
+ return getCollectionFormatForParam(
1156
+ context,
1157
+ param,
1158
+ optionalParamName,
1159
+ serializedName
1160
+ );
893
1161
  }
894
1162
 
895
1163
  // if the parameter or property is optional, we don't need to handle the default value
896
1164
  if (isOptional(param)) {
897
- return getOptional(context, param, optionalParamName);
1165
+ return getOptional(context, param, optionalParamName, serializedName);
898
1166
  }
899
1167
 
900
1168
  if (isRequired(param)) {
901
- return getRequired(context, param);
1169
+ return getRequired(context, param, serializedName);
902
1170
  }
903
1171
 
904
1172
  reportDiagnostic(context.program, {
@@ -917,9 +1185,9 @@ export function getParameterMap(
917
1185
  function getCollectionFormatForParam(
918
1186
  context: SdkContext,
919
1187
  param: SdkHttpParameter,
920
- optionalParamName: string = "options"
1188
+ optionalParamName: string = "options",
1189
+ serializedName: string
921
1190
  ) {
922
- const serializedName = getPropertySerializedName(param);
923
1191
  const format = (param as any).collectionFormat;
924
1192
  return `"${serializedName}": ${serializeRequestValue(
925
1193
  context,
@@ -963,8 +1231,11 @@ function isRequired(param: SdkHttpParameter) {
963
1231
  return !param.optional;
964
1232
  }
965
1233
 
966
- function getRequired(context: SdkContext, param: SdkHttpParameter) {
967
- const serializedName = getPropertySerializedName(param);
1234
+ function getRequired(
1235
+ context: SdkContext,
1236
+ param: SdkHttpParameter,
1237
+ serializedName: string
1238
+ ) {
968
1239
  const clientValue = `${param.onClient ? "context." : ""}${param.name}`;
969
1240
  if (param.type.kind === "model") {
970
1241
  const propertiesStr = getRequestModelMapping(
@@ -1003,9 +1274,9 @@ function isOptional(param: SdkHttpParameter) {
1003
1274
  function getOptional(
1004
1275
  context: SdkContext,
1005
1276
  param: SdkHttpParameter,
1006
- optionalParamName: string
1277
+ optionalParamName: string,
1278
+ serializedName: string
1007
1279
  ) {
1008
- const serializedName = getPropertySerializedName(param);
1009
1280
  const paramName = `${param.onClient ? "context." : `${optionalParamName}?.`}${param.name}`;
1010
1281
  if (param.type.kind === "model") {
1011
1282
  const propertiesStr = getRequestModelMapping(
@@ -1171,8 +1442,8 @@ function getEncodeForModelProperty(
1171
1442
  property: SdkModelPropertyType
1172
1443
  ): string | undefined {
1173
1444
  if (property.encode && property.type.kind === "array") {
1174
- // Only arrays of string type can have collectionFormat encoding
1175
- if (property.type.valueType.kind !== "string") {
1445
+ // Only arrays of string type or string-based enum type can have collectionFormat encoding
1446
+ if (!isStringEncodableArrayValueType(property.type.valueType)) {
1176
1447
  reportDiagnostic(context.program, {
1177
1448
  code: "un-supported-array-encoding",
1178
1449
  format: {
@@ -1197,6 +1468,25 @@ function getEncodeForModelProperty(
1197
1468
  return getEncodeForType(property.type);
1198
1469
  }
1199
1470
 
1471
+ /**
1472
+ * Checks if an array value type is string-encodable for collection format encoding.
1473
+ * This includes both string type and string-based enum types.
1474
+ */
1475
+ function isStringEncodableArrayValueType(valueType: SdkType): boolean {
1476
+ // Direct string type
1477
+ if (valueType.kind === "string") {
1478
+ return true;
1479
+ }
1480
+ // String-based enum type
1481
+ if (
1482
+ valueType.kind === "enum" &&
1483
+ (valueType as SdkEnumType).valueType.kind === "string"
1484
+ ) {
1485
+ return true;
1486
+ }
1487
+ return false;
1488
+ }
1489
+
1200
1490
  function getSerializationExpressionForFlatten(
1201
1491
  context: SdkContext,
1202
1492
  property: SdkModelPropertyType,
@@ -1336,6 +1626,14 @@ function getPropertySerializedName(
1336
1626
  );
1337
1627
  }
1338
1628
 
1629
+ /**
1630
+ * Get the serialized name for a header parameter, normalized to lowercase.
1631
+ * HTTP headers are case-insensitive, so we normalize to lowercase for consistency.
1632
+ */
1633
+ function getHeaderSerializedName(param: SdkHttpParameter) {
1634
+ return getPropertySerializedName(param).toLowerCase();
1635
+ }
1636
+
1339
1637
  /**
1340
1638
  * This function helps translating an RLC response to an HLC response,
1341
1639
  * extracting properties from body and headers and building the HLC response object
@@ -1589,7 +1887,15 @@ export function deserializeResponseValue(
1589
1887
  isTypeNullable(type) || getOptionalForType(type) || !required
1590
1888
  ? `${restValue} === null || ${restValue} === undefined ? ${restValue}: `
1591
1889
  : "";
1592
- return `${optionalPrefixForString}${parseHelper}(${restValue})`;
1890
+ if (
1891
+ type.valueType.kind === "enum" &&
1892
+ !isExtensibleEnum(context, type.valueType)
1893
+ ) {
1894
+ // Special handling for non-extensible enums to cast the result to the correct type
1895
+ return `${optionalPrefixForString}${parseHelper}(${restValue}) as ${getTypeExpression(context, type)}`;
1896
+ } else {
1897
+ return `${optionalPrefixForString}${parseHelper}(${restValue})`;
1898
+ }
1593
1899
  }
1594
1900
  }
1595
1901
  return `${prefix}.map((${varName}: any) => { return ${elementNullOrUndefinedPrefix}${deserializeResponseValue(context, type.valueType, varName, true, getEncodeForType(type.valueType), recursionDepth + 1)}})`;
@@ -1743,9 +2049,13 @@ export function getPropertyFullName(
1743
2049
  property: SdkHttpParameter | SdkModelPropertyType,
1744
2050
  propertyPath?: string
1745
2051
  ) {
1746
- const normalizedPropertyName = normalizeModelPropertyName(context, property)
1747
- .replace(/^"/g, "")
1748
- .replace(/"$/g, "");
2052
+ const normalizedPropertyName =
2053
+ propertyPath === ""
2054
+ ? normalizeName(property.name, NameType.Parameter, true)
2055
+ : normalizeModelPropertyName(context, property)
2056
+ .replace(/^"/g, "")
2057
+ .replace(/"$/g, "");
2058
+
1749
2059
  let fullName = normalizedPropertyName;
1750
2060
  if (propertyPath === "" && property.optional) {
1751
2061
  fullName = `options?.${normalizedPropertyName}`;
@@ -1762,8 +2072,18 @@ export function getPropertyFullName(
1762
2072
  export function getExpectedStatuses(operation: ServiceOperation): string {
1763
2073
  let statusCodes = operation.operation.responses.map((x) => x.statusCodes);
1764
2074
  // LROs may call the same path but with GET to get the operation status.
1765
- if (isLroOnlyOperation(operation) && operation.operation.verb !== "get") {
1766
- statusCodes = Array.from(new Set([...statusCodes, 200, 201, 202]));
2075
+ if (
2076
+ (isLroOnlyOperation(operation) || isLroAndPagingOperation(operation)) &&
2077
+ operation.operation.verb !== "get"
2078
+ ) {
2079
+ // DELETE: Add 200, 202 for polling
2080
+ // POST/PUT/PATCH: Add 200, 201, 202 for polling
2081
+ const verb = operation.operation.verb.toLowerCase();
2082
+ if (verb === "delete") {
2083
+ statusCodes = Array.from(new Set([...statusCodes, 200, 202]));
2084
+ } else {
2085
+ statusCodes = Array.from(new Set([...statusCodes, 200, 201, 202]));
2086
+ }
1767
2087
  }
1768
2088
 
1769
2089
  return `[${statusCodes.map((x) => `"${x}"`).join(", ")}]`;