@azure-tools/typespec-ts 0.49.0 → 0.49.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 (106) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/dist/src/framework/hooks/binder.d.ts.map +1 -1
  3. package/dist/src/framework/hooks/binder.js +8 -17
  4. package/dist/src/framework/hooks/binder.js.map +1 -1
  5. package/dist/src/index.d.ts.map +1 -1
  6. package/dist/src/index.js +13 -11
  7. package/dist/src/index.js.map +1 -1
  8. package/dist/src/lib.d.ts +8 -0
  9. package/dist/src/lib.d.ts.map +1 -1
  10. package/dist/src/lib.js +10 -0
  11. package/dist/src/lib.js.map +1 -1
  12. package/dist/src/modular/buildOperations.d.ts.map +1 -1
  13. package/dist/src/modular/buildOperations.js +10 -5
  14. package/dist/src/modular/buildOperations.js.map +1 -1
  15. package/dist/src/modular/buildProjectFiles.d.ts.map +1 -1
  16. package/dist/src/modular/buildProjectFiles.js +13 -10
  17. package/dist/src/modular/buildProjectFiles.js.map +1 -1
  18. package/dist/src/modular/emitModels.d.ts.map +1 -1
  19. package/dist/src/modular/emitModels.js +43 -40
  20. package/dist/src/modular/emitModels.js.map +1 -1
  21. package/dist/src/modular/emitSamples.d.ts.map +1 -1
  22. package/dist/src/modular/emitSamples.js +9 -0
  23. package/dist/src/modular/emitSamples.js.map +1 -1
  24. package/dist/src/modular/helpers/clientHelpers.d.ts.map +1 -1
  25. package/dist/src/modular/helpers/clientHelpers.js +4 -1
  26. package/dist/src/modular/helpers/clientHelpers.js.map +1 -1
  27. package/dist/src/modular/helpers/namingHelpers.d.ts +7 -0
  28. package/dist/src/modular/helpers/namingHelpers.d.ts.map +1 -1
  29. package/dist/src/modular/helpers/namingHelpers.js +15 -0
  30. package/dist/src/modular/helpers/namingHelpers.js.map +1 -1
  31. package/dist/src/modular/helpers/operationHelpers.d.ts +19 -2
  32. package/dist/src/modular/helpers/operationHelpers.d.ts.map +1 -1
  33. package/dist/src/modular/helpers/operationHelpers.js +410 -39
  34. package/dist/src/modular/helpers/operationHelpers.js.map +1 -1
  35. package/dist/src/modular/serialization/buildDeserializerFunction.d.ts.map +1 -1
  36. package/dist/src/modular/serialization/buildDeserializerFunction.js +9 -3
  37. package/dist/src/modular/serialization/buildDeserializerFunction.js.map +1 -1
  38. package/dist/src/modular/serialization/buildXmlSerializerFunction.d.ts +12 -0
  39. package/dist/src/modular/serialization/buildXmlSerializerFunction.d.ts.map +1 -1
  40. package/dist/src/modular/serialization/buildXmlSerializerFunction.js +259 -18
  41. package/dist/src/modular/serialization/buildXmlSerializerFunction.js.map +1 -1
  42. package/dist/src/modular/static-helpers-metadata.d.ts +10 -0
  43. package/dist/src/modular/static-helpers-metadata.d.ts.map +1 -1
  44. package/dist/src/modular/static-helpers-metadata.js +10 -0
  45. package/dist/src/modular/static-helpers-metadata.js.map +1 -1
  46. package/dist/src/modular/type-expressions/get-model-expression.d.ts +3 -1
  47. package/dist/src/modular/type-expressions/get-model-expression.d.ts.map +1 -1
  48. package/dist/src/modular/type-expressions/get-model-expression.js +50 -9
  49. package/dist/src/modular/type-expressions/get-model-expression.js.map +1 -1
  50. package/dist/src/modular/type-expressions/get-nullable-expression.d.ts.map +1 -1
  51. package/dist/src/modular/type-expressions/get-nullable-expression.js +8 -0
  52. package/dist/src/modular/type-expressions/get-nullable-expression.js.map +1 -1
  53. package/dist/src/modular/type-expressions/get-type-expression.d.ts +3 -2
  54. package/dist/src/modular/type-expressions/get-type-expression.d.ts.map +1 -1
  55. package/dist/src/modular/type-expressions/get-type-expression.js.map +1 -1
  56. package/dist/src/transform/transform.d.ts.map +1 -1
  57. package/dist/src/transform/transform.js +10 -10
  58. package/dist/src/transform/transform.js.map +1 -1
  59. package/dist/src/transform/transformSchemas.d.ts.map +1 -1
  60. package/dist/src/transform/transformSchemas.js +4 -4
  61. package/dist/src/transform/transformSchemas.js.map +1 -1
  62. package/dist/src/transform/transfromRLCOptions.d.ts +1 -1
  63. package/dist/src/transform/transfromRLCOptions.d.ts.map +1 -1
  64. package/dist/src/transform/transfromRLCOptions.js +37 -24
  65. package/dist/src/transform/transfromRLCOptions.js.map +1 -1
  66. package/dist/src/utils/clientUtils.d.ts +1 -1
  67. package/dist/src/utils/clientUtils.d.ts.map +1 -1
  68. package/dist/src/utils/clientUtils.js +40 -17
  69. package/dist/src/utils/clientUtils.js.map +1 -1
  70. package/dist/src/utils/crossLanguageDef.d.ts.map +1 -1
  71. package/dist/src/utils/crossLanguageDef.js +9 -3
  72. package/dist/src/utils/crossLanguageDef.js.map +1 -1
  73. package/dist/src/utils/interfaces.d.ts +2 -1
  74. package/dist/src/utils/interfaces.d.ts.map +1 -1
  75. package/dist/src/utils/modelUtils.d.ts +2 -2
  76. package/dist/src/utils/modelUtils.d.ts.map +1 -1
  77. package/dist/src/utils/modelUtils.js +15 -16
  78. package/dist/src/utils/modelUtils.js.map +1 -1
  79. package/dist/tsconfig.tsbuildinfo +1 -1
  80. package/package.json +22 -22
  81. package/src/framework/hooks/binder.ts +12 -22
  82. package/src/index.ts +17 -10
  83. package/src/lib.ts +20 -0
  84. package/src/modular/buildOperations.ts +12 -4
  85. package/src/modular/buildProjectFiles.ts +19 -16
  86. package/src/modular/emitModels.ts +72 -44
  87. package/src/modular/emitSamples.ts +11 -1
  88. package/src/modular/helpers/clientHelpers.ts +5 -1
  89. package/src/modular/helpers/namingHelpers.ts +19 -0
  90. package/src/modular/helpers/operationHelpers.ts +533 -40
  91. package/src/modular/serialization/buildDeserializerFunction.ts +11 -2
  92. package/src/modular/serialization/buildXmlSerializerFunction.ts +375 -24
  93. package/src/modular/static-helpers-metadata.ts +10 -0
  94. package/src/modular/type-expressions/get-model-expression.ts +78 -13
  95. package/src/modular/type-expressions/get-nullable-expression.ts +9 -0
  96. package/src/modular/type-expressions/get-type-expression.ts +3 -1
  97. package/src/transform/transform.ts +5 -2
  98. package/src/transform/transformSchemas.ts +4 -1
  99. package/src/transform/transfromRLCOptions.ts +65 -24
  100. package/src/utils/clientUtils.ts +49 -16
  101. package/src/utils/crossLanguageDef.ts +8 -0
  102. package/src/utils/interfaces.ts +2 -1
  103. package/src/utils/modelUtils.ts +22 -18
  104. package/static/static-helpers/serialization/serialize-record.ts +3 -3
  105. package/static/static-helpers/serialization/xml-helpers.ts +91 -36
  106. package/static/static-helpers/urlTemplate.ts +5 -5
@@ -2,7 +2,7 @@ import { StructureKind } from "ts-morph";
2
2
  import { NoTarget } from "@typespec/compiler";
3
3
  import { PagingHelpers, PollingHelpers, SerializationHelpers, UrlTemplateHelpers, XmlHelpers } from "../static-helpers-metadata.js";
4
4
  import { getNullableValidType, isSpreadBodyParameter, isTypeNullable } from "./typeHelpers.js";
5
- import { getClassicalLayerPrefix, getOperationName } from "./namingHelpers.js";
5
+ import { getClassicalLayerPrefix, getOperationName, generateLocallyUniqueName } from "./namingHelpers.js";
6
6
  import { getCollectionFormatHelper, hasCollectionFormatInfo, isBinaryPayload, isXmlPayload, isMultipartPayload, hasDualFormatSupport, getCollectionFormatParseHelper, getCollectionFormatFromArrayEncoding, KnownCollectionFormat } from "../../utils/operationUtil.js";
7
7
  import { getPropertyWithOverrides, isNormalUnion, isSpecialHandledUnion } from "../serialization/serializeUtils.js";
8
8
  import { getDocsFromDescription, getFixmeForMultilineDocs } from "./docsHelpers.js";
@@ -18,11 +18,12 @@ import { useDependencies } from "../../framework/hooks/useDependencies.js";
18
18
  import { useSdkTypes } from "../../framework/hooks/sdkTypes.js";
19
19
  import { isAzureCoreErrorType } from "../../utils/modelUtils.js";
20
20
  import { getTypeExpression, normalizeModelPropertyName } from "../type-expressions/get-type-expression.js";
21
- import { isHttpMetadata, isReadOnly } from "@azure-tools/typespec-client-generator-core";
22
- import { isMetadata } from "@typespec/http";
21
+ import { getClientOptions, isHttpMetadata, isReadOnly } from "@azure-tools/typespec-client-generator-core";
22
+ import { isHeader, isMetadata } from "@typespec/http";
23
23
  import { useContext } from "../../contextManager.js";
24
24
  import { isExtensibleEnum } from "../type-expressions/get-enum-expression.js";
25
- export function getSendPrivateFunction(dpgContext, method, clientType) {
25
+ import { emitInlineModel } from "../type-expressions/get-model-expression.js";
26
+ export function getSendPrivateFunction(dpgContext, method, clientType, client) {
26
27
  const operation = method[1];
27
28
  const parameters = getOperationSignatureParameters(dpgContext, method, clientType);
28
29
  const { name } = getOperationName(operation);
@@ -44,12 +45,21 @@ export function getSendPrivateFunction(dpgContext, method, clientType) {
44
45
  ...getQueryParameters(dpgContext, operation)
45
46
  ];
46
47
  if (urlTemplateParams.length > 0) {
47
- statements.push(`const path = ${resolveReference(UrlTemplateHelpers.parseTemplate)}("${operation.operation.uriTemplate}", {
48
+ // Generate a unique local variable name that doesn't conflict with parameter names
49
+ const paramNames = new Set(parameters.map((p) => p.name));
50
+ const pathVarName = generateLocallyUniqueName("path", paramNames);
51
+ const includeRootSlash = client
52
+ ? getClientOptions(client, "includeRootSlash") !== false
53
+ : true;
54
+ const uriTemplate = includeRootSlash
55
+ ? operation.operation.uriTemplate
56
+ : operation.operation.uriTemplate.replace(/^\//, "");
57
+ statements.push(`const ${pathVarName} = ${resolveReference(UrlTemplateHelpers.parseTemplate)}("${uriTemplate}", {
48
58
  ${urlTemplateParams.join(",\n")}
49
59
  },{
50
60
  allowReserved: ${optionalParamName}?.requestOptions?.skipUrlEncoding
51
61
  });`);
52
- pathStr = "path";
62
+ pathStr = pathVarName;
53
63
  }
54
64
  statements.push(`return context.path(${pathStr}).${operationMethod}({...${resolveReference(dependencies.operationOptionsToRequestParameters)}(${optionalParamName}), ${getHeaderAndBodyParameters(dpgContext, operation, optionalParamName)}});`);
55
65
  return {
@@ -58,7 +68,7 @@ export function getSendPrivateFunction(dpgContext, method, clientType) {
58
68
  };
59
69
  }
60
70
  export function getDeserializePrivateFunction(context, operation) {
61
- var _a, _b, _c, _d, _e, _f, _g;
71
+ var _a, _b, _c, _d, _e, _f, _g, _h;
62
72
  const { name } = getOperationName(operation);
63
73
  const dependencies = useDependencies();
64
74
  const PathUncheckedResponseReference = resolveReference(dependencies.PathUncheckedResponse);
@@ -70,6 +80,7 @@ export function getDeserializePrivateFunction(context, operation) {
70
80
  ];
71
81
  const isLroOnly = isLroOnlyOperation(operation);
72
82
  const isLroAndPaging = isLroAndPagingOperation(operation);
83
+ const isPagingOnly = isPagingOnlyOperation(operation);
73
84
  // TODO: Support operation overloads
74
85
  // TODO: Support multiple responses
75
86
  const response = operation.response;
@@ -78,12 +89,20 @@ export function getDeserializePrivateFunction(context, operation) {
78
89
  if (isLroOnly || isLroAndPaging) {
79
90
  returnType = buildLroReturnType(context, operation);
80
91
  }
81
- else if (response.type && restResponse) {
92
+ else if (isPagingOnly && (restResponse === null || restResponse === void 0 ? void 0 : restResponse.type)) {
93
+ // For paging operations, use the full response model (e.g., _OperationListResult)
94
+ // instead of just the array element type
82
95
  returnType = {
83
96
  name: (_a = restResponse.name) !== null && _a !== void 0 ? _a : "",
84
97
  type: getTypeExpression(context, restResponse.type)
85
98
  };
86
99
  }
100
+ else if (response.type) {
101
+ returnType = {
102
+ name: (_b = response.name) !== null && _b !== void 0 ? _b : "",
103
+ type: getTypeExpression(context, response.type)
104
+ };
105
+ }
87
106
  else {
88
107
  returnType = { name: "", type: "void" };
89
108
  }
@@ -99,12 +118,12 @@ export function getDeserializePrivateFunction(context, operation) {
99
118
  statements.push(`const expectedStatuses = ${getExpectedStatuses(operation)};`);
100
119
  statements.push(`if(!expectedStatuses.includes(result.status)){`, `${getExceptionThrowStatement(context, operation)}`, "}");
101
120
  const deserializedType = isLroOnly || isLroAndPaging
102
- ? (_c = (_b = operation === null || operation === void 0 ? void 0 : operation.lroMetadata) === null || _b === void 0 ? void 0 : _b.finalResponse) === null || _c === void 0 ? void 0 : _c.result
103
- : restResponse
121
+ ? (_d = (_c = operation === null || operation === void 0 ? void 0 : operation.lroMetadata) === null || _c === void 0 ? void 0 : _c.finalResponse) === null || _d === void 0 ? void 0 : _d.result
122
+ : isPagingOnly && (restResponse === null || restResponse === void 0 ? void 0 : restResponse.type)
104
123
  ? restResponse.type
105
124
  : response.type;
106
125
  const lroSubSegments = isLroOnly
107
- ? (_e = (_d = operation === null || operation === void 0 ? void 0 : operation.lroMetadata) === null || _d === void 0 ? void 0 : _d.finalResponse) === null || _e === void 0 ? void 0 : _e.resultSegments
126
+ ? (_f = (_e = operation === null || operation === void 0 ? void 0 : operation.lroMetadata) === null || _e === void 0 ? void 0 : _e.finalResponse) === null || _f === void 0 ? void 0 : _f.resultSegments
108
127
  : undefined;
109
128
  let lroSubPath;
110
129
  if (lroSubSegments && lroSubSegments.length > 0) {
@@ -123,7 +142,7 @@ export function getDeserializePrivateFunction(context, operation) {
123
142
  `);
124
143
  }
125
144
  if (deserializedType) {
126
- const contentTypes = (_g = (_f = operation.operation.responses[0]) === null || _f === void 0 ? void 0 : _f.contentTypes) !== null && _g !== void 0 ? _g : [];
145
+ const contentTypes = (_h = (_g = operation.operation.responses[0]) === null || _g === void 0 ? void 0 : _g.contentTypes) !== null && _h !== void 0 ? _h : [];
127
146
  const isXml = isXmlPayload(contentTypes);
128
147
  const isDualFormat = hasDualFormatSupport(contentTypes);
129
148
  const isMultipart = isMultipartPayload(contentTypes);
@@ -216,9 +235,48 @@ export function getDeserializePrivateFunction(context, operation) {
216
235
  statements
217
236
  };
218
237
  }
238
+ /**
239
+ * Generates a private function to deserialize response headers.
240
+ * Only generated when response headers are present and include-headers-in-response is enabled.
241
+ */
242
+ export function getDeserializeHeadersPrivateFunction(context, operation) {
243
+ var _a;
244
+ const responseHeaders = getResponseHeaders(operation.operation.responses);
245
+ const isResponseHeadersEnabled = ((_a = context.rlcOptions) === null || _a === void 0 ? void 0 : _a.includeHeadersInResponse) === true;
246
+ // Only generate if headers exist and feature is enabled
247
+ if (responseHeaders.length === 0 || !isResponseHeadersEnabled) {
248
+ return undefined;
249
+ }
250
+ const { name } = getOperationName(operation);
251
+ const dependencies = useDependencies();
252
+ const PathUncheckedResponseReference = resolveReference(dependencies.PathUncheckedResponse);
253
+ const parameters = [
254
+ {
255
+ name: "result",
256
+ type: PathUncheckedResponseReference
257
+ }
258
+ ];
259
+ const returnType = buildHeaderOnlyResponseType(context, responseHeaders);
260
+ const functionStatement = {
261
+ isAsync: false,
262
+ isExported: true,
263
+ name: `_${name}DeserializeHeaders`,
264
+ parameters,
265
+ returnType
266
+ };
267
+ const statements = [];
268
+ statements.push(`return ${buildHeaderOnlyResponseValue(context, responseHeaders)};`);
269
+ return {
270
+ ...functionStatement,
271
+ statements
272
+ };
273
+ }
219
274
  function getExceptionDetails(context, operation) {
275
+ var _a;
220
276
  const customized = [];
221
277
  let defaultDeserializer;
278
+ let defaultXmlDeserializer;
279
+ let defaultIsXmlOnly;
222
280
  for (const exception of operation.operation.exceptions) {
223
281
  if (!exception.type) {
224
282
  continue;
@@ -232,56 +290,124 @@ function getExceptionDetails(context, operation) {
232
290
  typeof deserializeFunctionName !== "string") {
233
291
  continue;
234
292
  }
293
+ // Check if the exception type has XML serialization support
294
+ // Use exception contentTypes when available, otherwise check the type itself
295
+ const exceptionContentTypes = (_a = exception.contentTypes) !== null && _a !== void 0 ? _a : [];
296
+ const exceptionIsXml = isXmlPayload(exceptionContentTypes);
297
+ const exceptionIsDualFormat = hasDualFormatSupport(exceptionContentTypes);
298
+ const typeHasXml = exception.type.kind === "model" && hasXmlSerialization(exception.type);
299
+ let xmlDeserializerName;
300
+ if (exception.type.kind === "model" && (typeHasXml || exceptionIsXml)) {
301
+ const xmlName = buildXmlModelDeserializer(context, exception.type, {
302
+ nameOnly: true,
303
+ skipDiscriminatedUnionSuffix: false
304
+ });
305
+ if (typeof xmlName === "string") {
306
+ xmlDeserializerName = xmlName;
307
+ }
308
+ }
309
+ // XML-only when all content types are XML (no JSON support)
310
+ const isXmlOnly = xmlDeserializerName !== undefined &&
311
+ exceptionIsXml &&
312
+ !exceptionIsDualFormat;
235
313
  if (statusCode === "*") {
236
314
  defaultDeserializer = deserializeFunctionName;
315
+ defaultXmlDeserializer = xmlDeserializerName;
316
+ defaultIsXmlOnly = isXmlOnly;
237
317
  }
238
318
  else if (typeof statusCode === "number") {
239
319
  customized.push({
240
320
  start: statusCode,
241
- deserializer: deserializeFunctionName
321
+ deserializer: deserializeFunctionName,
322
+ xmlDeserializer: xmlDeserializerName,
323
+ isXmlOnly
242
324
  });
243
325
  }
244
326
  else {
245
327
  customized.push({
246
328
  start: statusCode.start,
247
329
  end: statusCode.end,
248
- deserializer: deserializeFunctionName
330
+ deserializer: deserializeFunctionName,
331
+ xmlDeserializer: xmlDeserializerName,
332
+ isXmlOnly
249
333
  });
250
334
  }
251
335
  }
252
- return { customized, defaultDeserializer };
336
+ return {
337
+ customized,
338
+ defaultDeserializer,
339
+ defaultXmlDeserializer,
340
+ defaultIsXmlOnly
341
+ };
342
+ }
343
+ function getExceptionDeserializeExpr(exception) {
344
+ if (!exception.xmlDeserializer) {
345
+ return `${exception.deserializer}(result.body)`;
346
+ }
347
+ if (exception.isXmlOnly) {
348
+ return `${exception.xmlDeserializer}(result.body)`;
349
+ }
350
+ return `isXml ? ${exception.xmlDeserializer}(result.body) : ${exception.deserializer}(result.body)`;
253
351
  }
254
352
  function getExceptionThrowStatement(context, operation) {
255
353
  const statements = [];
256
354
  const createRestErrorReference = resolveReference(useDependencies().createRestError);
257
- const { customized, defaultDeserializer } = getExceptionDetails(context, operation);
355
+ const { customized, defaultDeserializer, defaultXmlDeserializer, defaultIsXmlOnly } = getExceptionDetails(context, operation);
356
+ // Check if any exception has XML deserialization support that requires runtime content-type check
357
+ const hasAnyDualFormatXml = (defaultXmlDeserializer !== undefined && !defaultIsXmlOnly) ||
358
+ customized.some((e) => e.xmlDeserializer !== undefined && !e.isXmlOnly);
258
359
  if (customized.length > 0) {
259
360
  statements.push(`const error = ${createRestErrorReference}(result);`);
361
+ if (hasAnyDualFormatXml) {
362
+ const isXmlContentTypeRef = resolveReference(XmlHelpers.isXmlContentType);
363
+ statements.push(`const responseContentType = result.headers?.["content-type"] ?? "";`);
364
+ statements.push(`const isXml = ${isXmlContentTypeRef}(responseContentType);`);
365
+ }
260
366
  statements.push(`const statusCode = Number.parseInt(result.status);`);
261
367
  const stats = customized.map((exception) => {
368
+ const deserializeExpr = getExceptionDeserializeExpr(exception);
262
369
  if (exception.end) {
263
370
  return `if(statusCode >= ${exception.start} && statusCode <= ${exception.end}) {
264
- error.details = ${exception.deserializer}(result.body);
371
+ error.details = ${deserializeExpr};
265
372
  }`;
266
373
  }
267
374
  else {
268
375
  return `if(statusCode === ${exception.start}) {
269
- error.details = ${exception.deserializer}(result.body);
376
+ error.details = ${deserializeExpr};
270
377
  }`;
271
378
  }
272
379
  });
273
380
  statements.push(stats.join("\nelse "));
274
381
  if (defaultDeserializer) {
382
+ const defaultDeserializeExpr = !defaultXmlDeserializer
383
+ ? `${defaultDeserializer}(result.body)`
384
+ : defaultIsXmlOnly
385
+ ? `${defaultXmlDeserializer}(result.body)`
386
+ : `isXml ? ${defaultXmlDeserializer}(result.body) : ${defaultDeserializer}(result.body)`;
275
387
  statements.push(`else {
276
- error.details = ${defaultDeserializer}(result.body);
388
+ error.details = ${defaultDeserializeExpr};
277
389
  }`);
278
390
  }
279
391
  statements.push("throw error;");
280
392
  }
281
393
  else {
282
394
  if (defaultDeserializer) {
283
- statements.push(`const error = ${createRestErrorReference}(result);
284
- error.details = ${defaultDeserializer}(result.body);`);
395
+ if (defaultXmlDeserializer) {
396
+ if (defaultIsXmlOnly) {
397
+ statements.push(`const error = ${createRestErrorReference}(result);
398
+ error.details = ${defaultXmlDeserializer}(result.body);`);
399
+ }
400
+ else {
401
+ const isXmlContentTypeRef = resolveReference(XmlHelpers.isXmlContentType);
402
+ statements.push(`const error = ${createRestErrorReference}(result);
403
+ const responseContentType = result.headers?.["content-type"] ?? "";
404
+ error.details = ${isXmlContentTypeRef}(responseContentType) ? ${defaultXmlDeserializer}(result.body) : ${defaultDeserializer}(result.body);`);
405
+ }
406
+ }
407
+ else {
408
+ statements.push(`const error = ${createRestErrorReference}(result);
409
+ error.details = ${defaultDeserializer}(result.body);`);
410
+ }
285
411
  statements.push("throw error;");
286
412
  }
287
413
  else {
@@ -309,7 +435,6 @@ function getOperationSignatureParameters(context, method, clientType) {
309
435
  ((_a = param.methodParameterSegments[0]) === null || _a === void 0 ? void 0 : _a.length) === 1 &&
310
436
  ((_b = param.methodParameterSegments[0]) === null || _b === void 0 ? void 0 : _b[0]) === p);
311
437
  })[0]) === null || _a === void 0 ? void 0 : _a.kind) !== "cookie" &&
312
- p.clientDefaultValue === undefined &&
313
438
  !p.optional &&
314
439
  !(p.isGeneratedName &&
315
440
  (p.name === "contentType" || p.name === "accept"));
@@ -339,7 +464,7 @@ function getOperationSignatureParameters(context, method, clientType) {
339
464
  * This operation builds and returns the function declaration for an operation.
340
465
  */
341
466
  export function getOperationFunction(context, method, clientType) {
342
- var _a, _b;
467
+ var _a, _b, _c, _d;
343
468
  const operation = method[1];
344
469
  // Extract required parameters
345
470
  const parameters = getOperationSignatureParameters(context, method, clientType);
@@ -358,12 +483,34 @@ export function getOperationFunction(context, method, clientType) {
358
483
  }
359
484
  // TODO: Support operation overloads
360
485
  const response = operation.response;
486
+ const responseHeaders = getResponseHeaders(operation.operation.responses);
487
+ const hasHeaderOnlyResponse = !response.type && responseHeaders.length > 0;
488
+ const isResponseHeadersEnabled = ((_a = context.rlcOptions) === null || _a === void 0 ? void 0 : _a.includeHeadersInResponse) === true;
361
489
  let returnType = { name: "", type: "void" };
362
490
  if (response.type) {
363
491
  const type = response.type;
492
+ // If feature flag enabled, we'll append the response headers to the operation response type.
493
+ if (type.kind === "model" &&
494
+ responseHeaders.length > 0 &&
495
+ isResponseHeadersEnabled) {
496
+ // Build a composite type that includes both model and additional header properties
497
+ returnType = {
498
+ name: (_b = type.name) !== null && _b !== void 0 ? _b : "",
499
+ type: `${buildCompositeResponseType(context, type, responseHeaders)}`
500
+ };
501
+ }
502
+ else {
503
+ returnType = {
504
+ name: (_c = type.name) !== null && _c !== void 0 ? _c : "",
505
+ type: getTypeExpression(context, type)
506
+ };
507
+ }
508
+ }
509
+ else if (hasHeaderOnlyResponse && isResponseHeadersEnabled) {
510
+ // Here we handle returning headers when the operation return type is void
364
511
  returnType = {
365
- name: (_a = type.name) !== null && _a !== void 0 ? _a : "",
366
- type: getTypeExpression(context, type)
512
+ name: "",
513
+ type: `${buildHeaderOnlyResponseType(context, responseHeaders)}`
367
514
  };
368
515
  }
369
516
  const { name, fixme = [] } = getOperationName(operation);
@@ -381,17 +528,37 @@ export function getOperationFunction(context, method, clientType) {
381
528
  returnType: `Promise<${returnType.type}>`
382
529
  };
383
530
  const statements = [];
531
+ // Generate unique local variable names that don't conflict with parameter names
532
+ const paramNames = new Set(parameters.map((p) => p.name));
533
+ const resultVarName = generateLocallyUniqueName("result", paramNames);
384
534
  const parameterList = parameters.map((p) => p.name).join(", ");
385
535
  // Special case for binary-only bodies: use helper to call streaming methods so that Core doesn't poison the response body by
386
536
  // doing a UTF-8 decode on the raw bytes.
387
- if (((_b = response === null || response === void 0 ? void 0 : response.type) === null || _b === void 0 ? void 0 : _b.kind) === "bytes" && response.type.encode === "bytes") {
388
- statements.push(`const streamableMethod = _${name}Send(${parameterList});`);
389
- statements.push(`const result = await ${resolveReference(SerializationHelpers.getBinaryResponse)}(streamableMethod);`);
537
+ if (((_d = response === null || response === void 0 ? void 0 : response.type) === null || _d === void 0 ? void 0 : _d.kind) === "bytes" && response.type.encode === "bytes") {
538
+ const streamableMethodVarName = generateLocallyUniqueName("streamableMethod", paramNames);
539
+ statements.push(`const ${streamableMethodVarName} = _${name}Send(${parameterList});`);
540
+ statements.push(`const ${resultVarName} = await ${resolveReference(SerializationHelpers.getBinaryResponse)}(${streamableMethodVarName});`);
390
541
  }
391
542
  else {
392
- statements.push(`const result = await _${name}Send(${parameterList});`);
543
+ statements.push(`const ${resultVarName} = await _${name}Send(${parameterList});`);
544
+ }
545
+ // If the response has headers and the feature flag to include headers in response is enabled, build the headers object and include it in the return value
546
+ if (responseHeaders.length > 0 && isResponseHeadersEnabled) {
547
+ const headersVarName = generateLocallyUniqueName("headers", paramNames);
548
+ statements.push(`const ${headersVarName} = _${name}DeserializeHeaders(result);`);
549
+ // If there is no body payload just return the headers
550
+ if (hasHeaderOnlyResponse) {
551
+ statements.push(`return {...${headersVarName} };`);
552
+ }
553
+ else {
554
+ const payloadVarName = generateLocallyUniqueName("payload", paramNames);
555
+ statements.push(`const ${payloadVarName} = await _${name}Deserialize(${resultVarName});`);
556
+ statements.push(`return { ...${payloadVarName}, ...${headersVarName} };`);
557
+ }
558
+ }
559
+ else {
560
+ statements.push(`return _${name}Deserialize(${resultVarName});`);
393
561
  }
394
- statements.push(`return _${name}Deserialize(result);`);
395
562
  return {
396
563
  ...functionStatement,
397
564
  statements
@@ -434,7 +601,7 @@ function getLroOnlyOperationFunction(context, method, clientType, optionalParamN
434
601
  allowedFinalLocation.includes(lroMetadata === null || lroMetadata === void 0 ? void 0 : lroMetadata.finalStateVia)
435
602
  ? `resourceLocationConfig: "${lroMetadata === null || lroMetadata === void 0 ? void 0 : lroMetadata.finalStateVia}",`
436
603
  : "";
437
- const apiVersion = getApiVersionExpression(operation);
604
+ const apiVersion = getApiVersionExpression(context, operation);
438
605
  const statements = [];
439
606
  statements.push(`
440
607
 
@@ -460,7 +627,7 @@ function getLroAndPagingOperationFunction(context, method, clientType, optionalP
460
627
  const { name, fixme = [] } = getOperationName(operation);
461
628
  const returnType = buildLroPagingReturnType(context, operation);
462
629
  // Get apiVersion expression for both LRO poller and paging options
463
- const apiVersion = getApiVersionExpression(operation);
630
+ const apiVersion = getApiVersionExpression(context, operation);
464
631
  // Build paging options from metadata
465
632
  const pagingOptions = [
466
633
  operation.response.resultSegments &&
@@ -593,7 +760,7 @@ function getPagingOnlyOperationFunction(context, method, clientType) {
593
760
  }).join(".");
594
761
  // Check for nextLinkVerb from TCGC pagingMetadata (supports @Legacy.nextLinkVerb decorator)
595
762
  const nextLinkMethod = operation.pagingMetadata.nextLinkVerb;
596
- const apiVersion = getApiVersionExpression(operation);
763
+ const apiVersion = getApiVersionExpression(context, operation);
597
764
  if (itemName) {
598
765
  options.push(`itemName: "${itemName}"`);
599
766
  }
@@ -726,10 +893,23 @@ function buildBodyParameter(context, bodyParameter, optionalParamName = "options
726
893
  });
727
894
  }
728
895
  const bodyParamName = normalizeName(bodyParameter.name, NameType.Parameter, true);
729
- const bodyNameExpression = bodyParameter.optional
896
+ let bodyNameExpression = bodyParameter.optional
730
897
  ? `${optionalParamName}["${bodyParamName}"]`
731
898
  : bodyParamName;
732
- const nullOrUndefinedPrefix = getPropertySerializationPrefix(context, bodyParameter, bodyParameter.optional ? optionalParamName : undefined);
899
+ // Check if body parameter has a client default value with matching type
900
+ const hasClientDefault = bodyParameter.optional &&
901
+ bodyParameter.clientDefaultValue !== undefined &&
902
+ isDefaultValueTypeMatch(bodyParameter, bodyParameter.clientDefaultValue);
903
+ // Apply client default value if present for optional body parameters
904
+ if (hasClientDefault) {
905
+ const formattedDefault = formatDefaultValue(bodyParameter.clientDefaultValue);
906
+ bodyNameExpression = `(${bodyNameExpression} ?? ${formattedDefault})`;
907
+ }
908
+ // Only apply nullOrUndefinedPrefix if there's no client default value
909
+ // because the default value already handles null/undefined cases
910
+ const nullOrUndefinedPrefix = hasClientDefault
911
+ ? ""
912
+ : getPropertySerializationPrefix(context, bodyParameter, bodyParameter.optional ? optionalParamName : undefined);
733
913
  // For dual-format operations, check the contentType option at runtime
734
914
  if (isDualFormat &&
735
915
  bodyType.kind === "model" &&
@@ -771,6 +951,7 @@ function getEncodingFormat(type) {
771
951
  * This function helps with renames, translating client names to rest api names
772
952
  */
773
953
  export function getParameterMap(context, param, optionalParamName = "options") {
954
+ var _a;
774
955
  // Use lowercase for header names since HTTP headers are case-insensitive
775
956
  const serializedName = param.kind === "header"
776
957
  ? getHeaderSerializedName(param)
@@ -780,6 +961,10 @@ export function getParameterMap(context, param, optionalParamName = "options") {
780
961
  }
781
962
  // Special case for api-version parameters with default values
782
963
  if (param.isApiVersionParam && param.clientDefaultValue) {
964
+ // For multi-service, use only the default value (don't reference context.apiVersion)
965
+ if ((_a = context.rlcOptions) === null || _a === void 0 ? void 0 : _a.isMultiService) {
966
+ return `"${serializedName}": "${param.clientDefaultValue}"`;
967
+ }
783
968
  return `"${serializedName}": ${param.onClient ? "context." : ""}${param.name} ?? "${param.clientDefaultValue}"`;
784
969
  }
785
970
  if (hasCollectionFormatInfo(param.kind, param.collectionFormat)) {
@@ -822,7 +1007,7 @@ function getContentTypeValue(param, optionalParamName = "options") {
822
1007
  }
823
1008
  else {
824
1009
  return `contentType: ${!param.optional
825
- ? "contentType"
1010
+ ? normalizeName(param.name, NameType.Property)
826
1011
  : `${optionalParamName}.` + param.name + " as any"}`;
827
1012
  }
828
1013
  }
@@ -851,12 +1036,18 @@ function isOptional(param) {
851
1036
  }
852
1037
  function getOptional(context, param, optionalParamName, serializedName) {
853
1038
  const paramName = `${param.onClient ? "context." : `${optionalParamName}?.`}${param.name}`;
1039
+ // Apply client default value if present and type matches
1040
+ const defaultSuffix = param.clientDefaultValue !== undefined &&
1041
+ isDefaultValueTypeMatch(param, param.clientDefaultValue)
1042
+ ? ` ?? ${formatDefaultValue(param.clientDefaultValue)}`
1043
+ : "";
854
1044
  if (param.type.kind === "model") {
855
1045
  const propertiesStr = getRequestModelMapping(context, { ...param.type, optional: param.optional }, paramName + "?.");
856
1046
  const serializeContent = `{${propertiesStr.join(",")}}`;
857
1047
  return `"${serializedName}": ${serializeContent}`;
858
1048
  }
859
- return `"${serializedName}": ${serializeRequestValue(context, param.type, paramName, false, getEncodeForType(param.type), serializedName, true)}`;
1049
+ const serializedValue = serializeRequestValue(context, param.type, paramName, false, getEncodeForType(param.type), serializedName, true);
1050
+ return `"${serializedName}": ${serializedValue}${defaultSuffix}`;
860
1051
  }
861
1052
  /**
862
1053
  * Get the encode for SDK type
@@ -1068,7 +1259,7 @@ export function getRequestModelProperties(context, modelPropertyType, propertyPa
1068
1259
  export function getRequestModelMapping(context, modelPropertyType, propertyPath = "body", overrides, enableFlatten = true) {
1069
1260
  return getRequestModelProperties(context, modelPropertyType, propertyPath, overrides, enableFlatten).map(([name, value]) => `"${name}": ${value}`);
1070
1261
  }
1071
- function getPropertySerializedName(property) {
1262
+ export function getPropertySerializedName(property) {
1072
1263
  var _a, _b;
1073
1264
  return ((_b = (property.kind === "property"
1074
1265
  ? (_a = property.serializationOptions.json) === null || _a === void 0 ? void 0 : _a.name
@@ -1227,6 +1418,63 @@ export function serializeRequestValue(context, type, clientValue, required, form
1227
1418
  return clientValue;
1228
1419
  }
1229
1420
  }
1421
+ /**
1422
+ * Wrapper of deserializeResponseValue, this is used to handle the special cases for response header deserialization, since response header only supports primitive types, we will have a simpler deserialization logic comparing to response body, and we also need to handle the null/undefined cases differently since if a header is missing, the value will be undefined instead of null.
1423
+ * Note: that this has been added to isolate these changes behind the feature flag. Once the feature flag is removed, we can consider merging this back to deserializeResponseValue if the special handling logic is not needed anymore.
1424
+ */
1425
+ export function deserializeResponseHeadersValue(context, type, restValue, required, format, recursionDepth = 0) {
1426
+ const nullOrUndefinedPrefix = isTypeNullable(type) || getOptionalForType(type) || !required
1427
+ ? `${restValue} === undefined || ${restValue} === null ? ${restValue}: `
1428
+ : "";
1429
+ switch (type.kind) {
1430
+ case "constant":
1431
+ return `${restValue} as any`;
1432
+ case "boolean":
1433
+ return `${nullOrUndefinedPrefix} ${restValue}.trim().toLowerCase() === "true"`;
1434
+ case "int16":
1435
+ case "int32":
1436
+ case "int64":
1437
+ case "uint16":
1438
+ case "uint32":
1439
+ case "uint64":
1440
+ case "float":
1441
+ case "decimal":
1442
+ case "decimal128":
1443
+ case "float32":
1444
+ case "float64":
1445
+ case "int8":
1446
+ case "integer":
1447
+ case "numeric":
1448
+ case "safeint":
1449
+ case "uint8":
1450
+ return `${nullOrUndefinedPrefix} Number(${restValue})`;
1451
+ case "enum":
1452
+ if (isNormalUnion(type)) {
1453
+ return `${restValue}`;
1454
+ }
1455
+ else if (isSpecialHandledUnion(type)) {
1456
+ const deserializeFunctionName = type
1457
+ ? buildModelDeserializer(context, getNullableValidType(type), {
1458
+ nameOnly: true,
1459
+ skipDiscriminatedUnionSuffix: false
1460
+ })
1461
+ : undefined;
1462
+ if (deserializeFunctionName) {
1463
+ return `${deserializeFunctionName}(${restValue})`;
1464
+ }
1465
+ else {
1466
+ return `${restValue} as any`;
1467
+ }
1468
+ }
1469
+ else {
1470
+ return `${restValue} as any`;
1471
+ }
1472
+ default: {
1473
+ const val = deserializeResponseValue(context, type, restValue, true, format, recursionDepth);
1474
+ return `${nullOrUndefinedPrefix} ${val}`;
1475
+ }
1476
+ }
1477
+ }
1230
1478
  /**
1231
1479
  * This function helps converting strings into JS complex types recursively.
1232
1480
  * We need to drill down into Array elements to make sure that the element type is
@@ -1391,6 +1639,43 @@ export function getAllAncestors(type) {
1391
1639
  }
1392
1640
  return ancestors;
1393
1641
  }
1642
+ /**
1643
+ * Checks if a clientDefaultValue type matches the parameter type.
1644
+ * Returns true if the default value type is compatible with the parameter type.
1645
+ */
1646
+ function isDefaultValueTypeMatch(param, defaultValue) {
1647
+ const defaultType = typeof defaultValue;
1648
+ const paramType = param.type;
1649
+ // Map JavaScript types to TypeSpec types
1650
+ if (defaultType === "string") {
1651
+ return paramType.kind === "string" || paramType.kind === "enum";
1652
+ }
1653
+ if (defaultType === "number") {
1654
+ return (paramType.kind === "int32" ||
1655
+ paramType.kind === "int64" ||
1656
+ paramType.kind === "float32" ||
1657
+ paramType.kind === "float64" ||
1658
+ paramType.kind === "numeric" ||
1659
+ paramType.kind === "integer" ||
1660
+ paramType.kind === "float" ||
1661
+ paramType.kind === "decimal");
1662
+ }
1663
+ if (defaultType === "boolean") {
1664
+ return paramType.kind === "boolean";
1665
+ }
1666
+ // For other types, don't apply the default
1667
+ return false;
1668
+ }
1669
+ /**
1670
+ * Formats a default value for code generation.
1671
+ * Strings are wrapped in quotes, other values are used as-is.
1672
+ */
1673
+ function formatDefaultValue(defaultValue) {
1674
+ if (typeof defaultValue === "string") {
1675
+ return `"${defaultValue}"`;
1676
+ }
1677
+ return String(defaultValue);
1678
+ }
1394
1679
  export function getPropertySerializationPrefix(context, property, propertyPath) {
1395
1680
  const propertyFullName = getPropertyFullName(context, property, propertyPath);
1396
1681
  if (property.optional || isTypeNullable(property.type)) {
@@ -1436,18 +1721,104 @@ export function getExpectedStatuses(operation) {
1436
1721
  }
1437
1722
  /**
1438
1723
  * Gets the apiVersion expression with default value fallback for query parameters.
1724
+ * @param dpgContext - The SDK context
1439
1725
  * @param operation - The operation to get the apiVersion parameter from
1440
1726
  * @returns The apiVersion expression string, or undefined if no apiVersion query param exists
1441
1727
  */
1442
- function getApiVersionExpression(operation) {
1728
+ function getApiVersionExpression(dpgContext, operation) {
1729
+ var _a;
1443
1730
  const queryApiVersionParam = operation.operation.parameters.find((p) => p.kind === "query" && p.isApiVersionParam);
1444
1731
  if (!queryApiVersionParam) {
1445
1732
  return undefined;
1446
1733
  }
1734
+ // For multi-service, use only the default value (don't reference context.apiVersion)
1735
+ if ((_a = dpgContext.rlcOptions) === null || _a === void 0 ? void 0 : _a.isMultiService) {
1736
+ return queryApiVersionParam.clientDefaultValue
1737
+ ? `"${queryApiVersionParam.clientDefaultValue}"`
1738
+ : undefined;
1739
+ }
1447
1740
  const paramAccess = `${queryApiVersionParam.onClient ? "context." : ""}${queryApiVersionParam.name}`;
1448
1741
  const defaultValueSuffix = queryApiVersionParam.clientDefaultValue
1449
1742
  ? ` ?? "${queryApiVersionParam.clientDefaultValue}"`
1450
1743
  : "";
1451
1744
  return `${paramAccess}${defaultValueSuffix}`;
1452
1745
  }
1746
+ /**
1747
+ * Extracts and deduplicates all response headers from operation responses.
1748
+ * @param responses - The operation responses
1749
+ * @returns Array of unique response headers
1750
+ */
1751
+ export function getResponseHeaders(responses) {
1752
+ var _a, _b;
1753
+ const headerMap = new Map();
1754
+ for (const response of responses !== null && responses !== void 0 ? responses : []) {
1755
+ for (const header of (_a = response.headers) !== null && _a !== void 0 ? _a : []) {
1756
+ const key = (_b = header.serializedName) !== null && _b !== void 0 ? _b : header.name;
1757
+ if (!headerMap.has(key)) {
1758
+ headerMap.set(key, header);
1759
+ }
1760
+ }
1761
+ }
1762
+ return Array.from(headerMap.values());
1763
+ }
1764
+ /**
1765
+ * Builds a composite return type for operations that return both a model and additional headers.
1766
+ * Combines model properties and header properties into an inline object type.
1767
+ * @param context - The SDK context
1768
+ * @param modelType - The model type
1769
+ * @param headers - The response headers that are NOT in the model
1770
+ * @returns The composite type expression as a string (e.g., "{ name: string; email: string; requestId: string }")
1771
+ */
1772
+ function buildCompositeResponseType(context, modelType, headers) {
1773
+ const allParents = getAllAncestors(modelType);
1774
+ const modelProps = getAllProperties(context, modelType, allParents);
1775
+ // Collect header property names already in the model to avoid duplicates
1776
+ const modelHeaderNames = new Set();
1777
+ for (const property of modelProps) {
1778
+ if (isHeader(context.program, property.__raw)) {
1779
+ modelHeaderNames.add(property.name.toLowerCase());
1780
+ }
1781
+ }
1782
+ // Add only additional host response header properties not already in model
1783
+ for (const header of headers) {
1784
+ if (modelHeaderNames.has(header.name.toLowerCase())) {
1785
+ continue;
1786
+ }
1787
+ modelProps.push(header);
1788
+ }
1789
+ return emitInlineModel(context, modelProps);
1790
+ }
1791
+ /**
1792
+ * Builds an inline type string for header-only responses.
1793
+ * @param context - The SDK context
1794
+ * @param headers - The response headers
1795
+ * @returns The inline type expression as a string (e.g., "{ requestId: string; optionalHeader?: string }")
1796
+ */
1797
+ function buildHeaderOnlyResponseType(context, headers) {
1798
+ const properties = [];
1799
+ for (const header of headers) {
1800
+ const headerName = normalizeModelPropertyName(context, header);
1801
+ const headerType = getTypeExpression(context, header.type);
1802
+ const isOptional = header.optional ? "?" : "";
1803
+ properties.push(`${headerName}${isOptional}: ${headerType}`);
1804
+ }
1805
+ return `{ ${properties.join("; ")} }`;
1806
+ }
1807
+ /**
1808
+ * Builds the object literal expression for a header-only response.
1809
+ * Handles type conversions for headers (string to boolean, Date, number, Uint8Array).
1810
+ * @param operation - The service operation
1811
+ * @param headers - The response headers
1812
+ * @returns JavaScript expression string for the header-only response object
1813
+ */
1814
+ function buildHeaderOnlyResponseValue(context, headers) {
1815
+ const props = headers.map((header) => {
1816
+ var _a;
1817
+ const headerName = ((_a = header.serializedName) !== null && _a !== void 0 ? _a : header.name).toLowerCase();
1818
+ const key = normalizeModelPropertyName(context, header);
1819
+ const value = deserializeResponseHeadersValue(context, header.type, `result.headers[${JSON.stringify(headerName)}]`, !header.optional, getEncodeForType(header.type), 0);
1820
+ return `${key}: ${value}`;
1821
+ });
1822
+ return `{ ${props.join(", ")} }`;
1823
+ }
1453
1824
  //# sourceMappingURL=operationHelpers.js.map