@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.
- package/CHANGELOG.md +24 -0
- package/dist/src/framework/hooks/binder.d.ts.map +1 -1
- package/dist/src/framework/hooks/binder.js +8 -17
- package/dist/src/framework/hooks/binder.js.map +1 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +13 -11
- package/dist/src/index.js.map +1 -1
- package/dist/src/lib.d.ts +8 -0
- package/dist/src/lib.d.ts.map +1 -1
- package/dist/src/lib.js +10 -0
- package/dist/src/lib.js.map +1 -1
- package/dist/src/modular/buildOperations.d.ts.map +1 -1
- package/dist/src/modular/buildOperations.js +10 -5
- package/dist/src/modular/buildOperations.js.map +1 -1
- package/dist/src/modular/buildProjectFiles.d.ts.map +1 -1
- package/dist/src/modular/buildProjectFiles.js +13 -10
- package/dist/src/modular/buildProjectFiles.js.map +1 -1
- package/dist/src/modular/emitModels.d.ts.map +1 -1
- package/dist/src/modular/emitModels.js +43 -40
- package/dist/src/modular/emitModels.js.map +1 -1
- package/dist/src/modular/emitSamples.d.ts.map +1 -1
- package/dist/src/modular/emitSamples.js +9 -0
- package/dist/src/modular/emitSamples.js.map +1 -1
- package/dist/src/modular/helpers/clientHelpers.d.ts.map +1 -1
- package/dist/src/modular/helpers/clientHelpers.js +4 -1
- package/dist/src/modular/helpers/clientHelpers.js.map +1 -1
- package/dist/src/modular/helpers/namingHelpers.d.ts +7 -0
- package/dist/src/modular/helpers/namingHelpers.d.ts.map +1 -1
- package/dist/src/modular/helpers/namingHelpers.js +15 -0
- package/dist/src/modular/helpers/namingHelpers.js.map +1 -1
- package/dist/src/modular/helpers/operationHelpers.d.ts +19 -2
- package/dist/src/modular/helpers/operationHelpers.d.ts.map +1 -1
- package/dist/src/modular/helpers/operationHelpers.js +410 -39
- package/dist/src/modular/helpers/operationHelpers.js.map +1 -1
- package/dist/src/modular/serialization/buildDeserializerFunction.d.ts.map +1 -1
- package/dist/src/modular/serialization/buildDeserializerFunction.js +9 -3
- package/dist/src/modular/serialization/buildDeserializerFunction.js.map +1 -1
- package/dist/src/modular/serialization/buildXmlSerializerFunction.d.ts +12 -0
- package/dist/src/modular/serialization/buildXmlSerializerFunction.d.ts.map +1 -1
- package/dist/src/modular/serialization/buildXmlSerializerFunction.js +259 -18
- package/dist/src/modular/serialization/buildXmlSerializerFunction.js.map +1 -1
- package/dist/src/modular/static-helpers-metadata.d.ts +10 -0
- package/dist/src/modular/static-helpers-metadata.d.ts.map +1 -1
- package/dist/src/modular/static-helpers-metadata.js +10 -0
- package/dist/src/modular/static-helpers-metadata.js.map +1 -1
- package/dist/src/modular/type-expressions/get-model-expression.d.ts +3 -1
- package/dist/src/modular/type-expressions/get-model-expression.d.ts.map +1 -1
- package/dist/src/modular/type-expressions/get-model-expression.js +50 -9
- package/dist/src/modular/type-expressions/get-model-expression.js.map +1 -1
- package/dist/src/modular/type-expressions/get-nullable-expression.d.ts.map +1 -1
- package/dist/src/modular/type-expressions/get-nullable-expression.js +8 -0
- package/dist/src/modular/type-expressions/get-nullable-expression.js.map +1 -1
- package/dist/src/modular/type-expressions/get-type-expression.d.ts +3 -2
- package/dist/src/modular/type-expressions/get-type-expression.d.ts.map +1 -1
- package/dist/src/modular/type-expressions/get-type-expression.js.map +1 -1
- package/dist/src/transform/transform.d.ts.map +1 -1
- package/dist/src/transform/transform.js +10 -10
- package/dist/src/transform/transform.js.map +1 -1
- package/dist/src/transform/transformSchemas.d.ts.map +1 -1
- package/dist/src/transform/transformSchemas.js +4 -4
- package/dist/src/transform/transformSchemas.js.map +1 -1
- package/dist/src/transform/transfromRLCOptions.d.ts +1 -1
- package/dist/src/transform/transfromRLCOptions.d.ts.map +1 -1
- package/dist/src/transform/transfromRLCOptions.js +37 -24
- package/dist/src/transform/transfromRLCOptions.js.map +1 -1
- package/dist/src/utils/clientUtils.d.ts +1 -1
- package/dist/src/utils/clientUtils.d.ts.map +1 -1
- package/dist/src/utils/clientUtils.js +40 -17
- package/dist/src/utils/clientUtils.js.map +1 -1
- package/dist/src/utils/crossLanguageDef.d.ts.map +1 -1
- package/dist/src/utils/crossLanguageDef.js +9 -3
- package/dist/src/utils/crossLanguageDef.js.map +1 -1
- package/dist/src/utils/interfaces.d.ts +2 -1
- package/dist/src/utils/interfaces.d.ts.map +1 -1
- package/dist/src/utils/modelUtils.d.ts +2 -2
- package/dist/src/utils/modelUtils.d.ts.map +1 -1
- package/dist/src/utils/modelUtils.js +15 -16
- package/dist/src/utils/modelUtils.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +22 -22
- package/src/framework/hooks/binder.ts +12 -22
- package/src/index.ts +17 -10
- package/src/lib.ts +20 -0
- package/src/modular/buildOperations.ts +12 -4
- package/src/modular/buildProjectFiles.ts +19 -16
- package/src/modular/emitModels.ts +72 -44
- package/src/modular/emitSamples.ts +11 -1
- package/src/modular/helpers/clientHelpers.ts +5 -1
- package/src/modular/helpers/namingHelpers.ts +19 -0
- package/src/modular/helpers/operationHelpers.ts +533 -40
- package/src/modular/serialization/buildDeserializerFunction.ts +11 -2
- package/src/modular/serialization/buildXmlSerializerFunction.ts +375 -24
- package/src/modular/static-helpers-metadata.ts +10 -0
- package/src/modular/type-expressions/get-model-expression.ts +78 -13
- package/src/modular/type-expressions/get-nullable-expression.ts +9 -0
- package/src/modular/type-expressions/get-type-expression.ts +3 -1
- package/src/transform/transform.ts +5 -2
- package/src/transform/transformSchemas.ts +4 -1
- package/src/transform/transfromRLCOptions.ts +65 -24
- package/src/utils/clientUtils.ts +49 -16
- package/src/utils/crossLanguageDef.ts +8 -0
- package/src/utils/interfaces.ts +2 -1
- package/src/utils/modelUtils.ts +22 -18
- package/static/static-helpers/serialization/serialize-record.ts +3 -3
- package/static/static-helpers/serialization/xml-helpers.ts +91 -36
- package/static/static-helpers/urlTemplate.ts +5 -5
|
@@ -17,7 +17,11 @@ import {
|
|
|
17
17
|
isSpreadBodyParameter,
|
|
18
18
|
isTypeNullable
|
|
19
19
|
} from "./typeHelpers.js";
|
|
20
|
-
import {
|
|
20
|
+
import {
|
|
21
|
+
getClassicalLayerPrefix,
|
|
22
|
+
getOperationName,
|
|
23
|
+
generateLocallyUniqueName
|
|
24
|
+
} from "./namingHelpers.js";
|
|
21
25
|
import {
|
|
22
26
|
getCollectionFormatHelper,
|
|
23
27
|
hasCollectionFormatInfo,
|
|
@@ -67,9 +71,11 @@ import {
|
|
|
67
71
|
} from "../type-expressions/get-type-expression.js";
|
|
68
72
|
import { SdkContext } from "../../utils/interfaces.js";
|
|
69
73
|
import {
|
|
74
|
+
getClientOptions,
|
|
70
75
|
isHttpMetadata,
|
|
71
76
|
isReadOnly,
|
|
72
77
|
SdkBodyParameter,
|
|
78
|
+
SdkClientType,
|
|
73
79
|
SdkConstantType,
|
|
74
80
|
SdkEnumType,
|
|
75
81
|
SdkHttpOperation,
|
|
@@ -81,16 +87,19 @@ import {
|
|
|
81
87
|
SdkModelPropertyType,
|
|
82
88
|
SdkModelType,
|
|
83
89
|
SdkPagingServiceMethod,
|
|
90
|
+
SdkServiceResponseHeader,
|
|
84
91
|
SdkType
|
|
85
92
|
} from "@azure-tools/typespec-client-generator-core";
|
|
86
|
-
import { isMetadata } from "@typespec/http";
|
|
93
|
+
import { isHeader, isMetadata } from "@typespec/http";
|
|
87
94
|
import { useContext } from "../../contextManager.js";
|
|
88
95
|
import { isExtensibleEnum } from "../type-expressions/get-enum-expression.js";
|
|
96
|
+
import { emitInlineModel } from "../type-expressions/get-model-expression.js";
|
|
89
97
|
|
|
90
98
|
export function getSendPrivateFunction(
|
|
91
99
|
dpgContext: SdkContext,
|
|
92
100
|
method: [string[], ServiceOperation],
|
|
93
|
-
clientType: string
|
|
101
|
+
clientType: string,
|
|
102
|
+
client?: SdkClientType<SdkHttpOperation>
|
|
94
103
|
): OptionalKind<FunctionDeclarationStructure> {
|
|
95
104
|
const operation = method[1];
|
|
96
105
|
const parameters = getOperationSignatureParameters(
|
|
@@ -119,12 +128,23 @@ export function getSendPrivateFunction(
|
|
|
119
128
|
...getQueryParameters(dpgContext, operation)
|
|
120
129
|
];
|
|
121
130
|
if (urlTemplateParams.length > 0) {
|
|
122
|
-
|
|
131
|
+
// Generate a unique local variable name that doesn't conflict with parameter names
|
|
132
|
+
const paramNames = new Set(parameters.map((p) => p.name));
|
|
133
|
+
const pathVarName = generateLocallyUniqueName("path", paramNames);
|
|
134
|
+
const includeRootSlash = client
|
|
135
|
+
? getClientOptions(client, "includeRootSlash") !== false
|
|
136
|
+
: true;
|
|
137
|
+
|
|
138
|
+
const uriTemplate = includeRootSlash
|
|
139
|
+
? operation.operation.uriTemplate
|
|
140
|
+
: operation.operation.uriTemplate.replace(/^\//, "");
|
|
141
|
+
|
|
142
|
+
statements.push(`const ${pathVarName} = ${resolveReference(UrlTemplateHelpers.parseTemplate)}("${uriTemplate}", {
|
|
123
143
|
${urlTemplateParams.join(",\n")}
|
|
124
144
|
},{
|
|
125
145
|
allowReserved: ${optionalParamName}?.requestOptions?.skipUrlEncoding
|
|
126
146
|
});`);
|
|
127
|
-
pathStr =
|
|
147
|
+
pathStr = pathVarName;
|
|
128
148
|
}
|
|
129
149
|
|
|
130
150
|
statements.push(
|
|
@@ -158,6 +178,7 @@ export function getDeserializePrivateFunction(
|
|
|
158
178
|
];
|
|
159
179
|
const isLroOnly = isLroOnlyOperation(operation);
|
|
160
180
|
const isLroAndPaging = isLroAndPagingOperation(operation);
|
|
181
|
+
const isPagingOnly = isPagingOnlyOperation(operation);
|
|
161
182
|
|
|
162
183
|
// TODO: Support operation overloads
|
|
163
184
|
// TODO: Support multiple responses
|
|
@@ -166,10 +187,17 @@ export function getDeserializePrivateFunction(
|
|
|
166
187
|
let returnType;
|
|
167
188
|
if (isLroOnly || isLroAndPaging) {
|
|
168
189
|
returnType = buildLroReturnType(context, operation);
|
|
169
|
-
} else if (
|
|
190
|
+
} else if (isPagingOnly && restResponse?.type) {
|
|
191
|
+
// For paging operations, use the full response model (e.g., _OperationListResult)
|
|
192
|
+
// instead of just the array element type
|
|
170
193
|
returnType = {
|
|
171
194
|
name: (restResponse as any).name ?? "",
|
|
172
|
-
type: getTypeExpression(context, restResponse.type
|
|
195
|
+
type: getTypeExpression(context, restResponse.type)
|
|
196
|
+
};
|
|
197
|
+
} else if (response.type) {
|
|
198
|
+
returnType = {
|
|
199
|
+
name: (response as any).name ?? "",
|
|
200
|
+
type: getTypeExpression(context, response.type)
|
|
173
201
|
};
|
|
174
202
|
} else {
|
|
175
203
|
returnType = { name: "", type: "void" };
|
|
@@ -198,7 +226,7 @@ export function getDeserializePrivateFunction(
|
|
|
198
226
|
const deserializedType =
|
|
199
227
|
isLroOnly || isLroAndPaging
|
|
200
228
|
? operation?.lroMetadata?.finalResponse?.result
|
|
201
|
-
: restResponse
|
|
229
|
+
: isPagingOnly && restResponse?.type
|
|
202
230
|
? restResponse.type
|
|
203
231
|
: response.type;
|
|
204
232
|
const lroSubSegments = isLroOnly
|
|
@@ -364,15 +392,72 @@ export function getDeserializePrivateFunction(
|
|
|
364
392
|
};
|
|
365
393
|
}
|
|
366
394
|
|
|
395
|
+
/**
|
|
396
|
+
* Generates a private function to deserialize response headers.
|
|
397
|
+
* Only generated when response headers are present and include-headers-in-response is enabled.
|
|
398
|
+
*/
|
|
399
|
+
export function getDeserializeHeadersPrivateFunction(
|
|
400
|
+
context: SdkContext,
|
|
401
|
+
operation: ServiceOperation
|
|
402
|
+
): OptionalKind<FunctionDeclarationStructure> | undefined {
|
|
403
|
+
const responseHeaders = getResponseHeaders(operation.operation.responses);
|
|
404
|
+
const isResponseHeadersEnabled =
|
|
405
|
+
context.rlcOptions?.includeHeadersInResponse === true;
|
|
406
|
+
|
|
407
|
+
// Only generate if headers exist and feature is enabled
|
|
408
|
+
if (responseHeaders.length === 0 || !isResponseHeadersEnabled) {
|
|
409
|
+
return undefined;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
const { name } = getOperationName(operation);
|
|
413
|
+
const dependencies = useDependencies();
|
|
414
|
+
const PathUncheckedResponseReference = resolveReference(
|
|
415
|
+
dependencies.PathUncheckedResponse
|
|
416
|
+
);
|
|
417
|
+
|
|
418
|
+
const parameters: OptionalKind<ParameterDeclarationStructure>[] = [
|
|
419
|
+
{
|
|
420
|
+
name: "result",
|
|
421
|
+
type: PathUncheckedResponseReference
|
|
422
|
+
}
|
|
423
|
+
];
|
|
424
|
+
|
|
425
|
+
const returnType = buildHeaderOnlyResponseType(context, responseHeaders);
|
|
426
|
+
|
|
427
|
+
const functionStatement: OptionalKind<FunctionDeclarationStructure> = {
|
|
428
|
+
isAsync: false,
|
|
429
|
+
isExported: true,
|
|
430
|
+
name: `_${name}DeserializeHeaders`,
|
|
431
|
+
parameters,
|
|
432
|
+
returnType
|
|
433
|
+
};
|
|
434
|
+
|
|
435
|
+
const statements: string[] = [];
|
|
436
|
+
statements.push(
|
|
437
|
+
`return ${buildHeaderOnlyResponseValue(context, responseHeaders)};`
|
|
438
|
+
);
|
|
439
|
+
|
|
440
|
+
return {
|
|
441
|
+
...functionStatement,
|
|
442
|
+
statements
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
|
|
367
446
|
interface ExceptionThrowDetail {
|
|
368
447
|
start: number;
|
|
369
448
|
end?: number;
|
|
370
449
|
deserializer: string;
|
|
450
|
+
xmlDeserializer?: string;
|
|
451
|
+
/** Whether the exception response is XML-only (no JSON content type) */
|
|
452
|
+
isXmlOnly?: boolean;
|
|
371
453
|
}
|
|
372
454
|
|
|
373
455
|
interface OperationExceptionDetails {
|
|
374
456
|
customized: ExceptionThrowDetail[];
|
|
375
457
|
defaultDeserializer?: string;
|
|
458
|
+
defaultXmlDeserializer?: string;
|
|
459
|
+
/** Whether the default exception response is XML-only */
|
|
460
|
+
defaultIsXmlOnly?: boolean;
|
|
376
461
|
}
|
|
377
462
|
|
|
378
463
|
function getExceptionDetails(
|
|
@@ -381,6 +466,8 @@ function getExceptionDetails(
|
|
|
381
466
|
): OperationExceptionDetails {
|
|
382
467
|
const customized: ExceptionThrowDetail[] = [];
|
|
383
468
|
let defaultDeserializer: string | undefined;
|
|
469
|
+
let defaultXmlDeserializer: string | undefined;
|
|
470
|
+
let defaultIsXmlOnly: boolean | undefined;
|
|
384
471
|
for (const exception of operation.operation.exceptions) {
|
|
385
472
|
if (!exception.type) {
|
|
386
473
|
continue;
|
|
@@ -400,22 +487,69 @@ function getExceptionDetails(
|
|
|
400
487
|
) {
|
|
401
488
|
continue;
|
|
402
489
|
}
|
|
490
|
+
|
|
491
|
+
// Check if the exception type has XML serialization support
|
|
492
|
+
// Use exception contentTypes when available, otherwise check the type itself
|
|
493
|
+
const exceptionContentTypes = exception.contentTypes ?? [];
|
|
494
|
+
const exceptionIsXml = isXmlPayload(exceptionContentTypes);
|
|
495
|
+
const exceptionIsDualFormat = hasDualFormatSupport(exceptionContentTypes);
|
|
496
|
+
const typeHasXml =
|
|
497
|
+
exception.type.kind === "model" && hasXmlSerialization(exception.type);
|
|
498
|
+
|
|
499
|
+
let xmlDeserializerName: string | undefined;
|
|
500
|
+
if (exception.type.kind === "model" && (typeHasXml || exceptionIsXml)) {
|
|
501
|
+
const xmlName = buildXmlModelDeserializer(context, exception.type, {
|
|
502
|
+
nameOnly: true,
|
|
503
|
+
skipDiscriminatedUnionSuffix: false
|
|
504
|
+
});
|
|
505
|
+
if (typeof xmlName === "string") {
|
|
506
|
+
xmlDeserializerName = xmlName;
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
// XML-only when all content types are XML (no JSON support)
|
|
511
|
+
const isXmlOnly =
|
|
512
|
+
xmlDeserializerName !== undefined &&
|
|
513
|
+
exceptionIsXml &&
|
|
514
|
+
!exceptionIsDualFormat;
|
|
515
|
+
|
|
403
516
|
if (statusCode === "*") {
|
|
404
517
|
defaultDeserializer = deserializeFunctionName;
|
|
518
|
+
defaultXmlDeserializer = xmlDeserializerName;
|
|
519
|
+
defaultIsXmlOnly = isXmlOnly;
|
|
405
520
|
} else if (typeof statusCode === "number") {
|
|
406
521
|
customized.push({
|
|
407
522
|
start: statusCode,
|
|
408
|
-
deserializer: deserializeFunctionName
|
|
523
|
+
deserializer: deserializeFunctionName,
|
|
524
|
+
xmlDeserializer: xmlDeserializerName,
|
|
525
|
+
isXmlOnly
|
|
409
526
|
});
|
|
410
527
|
} else {
|
|
411
528
|
customized.push({
|
|
412
529
|
start: statusCode.start,
|
|
413
530
|
end: statusCode.end,
|
|
414
|
-
deserializer: deserializeFunctionName
|
|
531
|
+
deserializer: deserializeFunctionName,
|
|
532
|
+
xmlDeserializer: xmlDeserializerName,
|
|
533
|
+
isXmlOnly
|
|
415
534
|
});
|
|
416
535
|
}
|
|
417
536
|
}
|
|
418
|
-
return {
|
|
537
|
+
return {
|
|
538
|
+
customized,
|
|
539
|
+
defaultDeserializer,
|
|
540
|
+
defaultXmlDeserializer,
|
|
541
|
+
defaultIsXmlOnly
|
|
542
|
+
};
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
function getExceptionDeserializeExpr(exception: ExceptionThrowDetail): string {
|
|
546
|
+
if (!exception.xmlDeserializer) {
|
|
547
|
+
return `${exception.deserializer}(result.body)`;
|
|
548
|
+
}
|
|
549
|
+
if (exception.isXmlOnly) {
|
|
550
|
+
return `${exception.xmlDeserializer}(result.body)`;
|
|
551
|
+
}
|
|
552
|
+
return `isXml ? ${exception.xmlDeserializer}(result.body) : ${exception.deserializer}(result.body)`;
|
|
419
553
|
}
|
|
420
554
|
|
|
421
555
|
function getExceptionThrowStatement(
|
|
@@ -426,35 +560,72 @@ function getExceptionThrowStatement(
|
|
|
426
560
|
const createRestErrorReference = resolveReference(
|
|
427
561
|
useDependencies().createRestError
|
|
428
562
|
);
|
|
429
|
-
const {
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
563
|
+
const {
|
|
564
|
+
customized,
|
|
565
|
+
defaultDeserializer,
|
|
566
|
+
defaultXmlDeserializer,
|
|
567
|
+
defaultIsXmlOnly
|
|
568
|
+
} = getExceptionDetails(context, operation);
|
|
569
|
+
|
|
570
|
+
// Check if any exception has XML deserialization support that requires runtime content-type check
|
|
571
|
+
const hasAnyDualFormatXml =
|
|
572
|
+
(defaultXmlDeserializer !== undefined && !defaultIsXmlOnly) ||
|
|
573
|
+
customized.some((e) => e.xmlDeserializer !== undefined && !e.isXmlOnly);
|
|
574
|
+
|
|
433
575
|
if (customized.length > 0) {
|
|
434
576
|
statements.push(`const error = ${createRestErrorReference}(result);`);
|
|
577
|
+
if (hasAnyDualFormatXml) {
|
|
578
|
+
const isXmlContentTypeRef = resolveReference(XmlHelpers.isXmlContentType);
|
|
579
|
+
statements.push(
|
|
580
|
+
`const responseContentType = result.headers?.["content-type"] ?? "";`
|
|
581
|
+
);
|
|
582
|
+
statements.push(
|
|
583
|
+
`const isXml = ${isXmlContentTypeRef}(responseContentType);`
|
|
584
|
+
);
|
|
585
|
+
}
|
|
435
586
|
statements.push(`const statusCode = Number.parseInt(result.status);`);
|
|
436
587
|
const stats: string[] = customized.map((exception) => {
|
|
588
|
+
const deserializeExpr = getExceptionDeserializeExpr(exception);
|
|
437
589
|
if (exception.end) {
|
|
438
590
|
return `if(statusCode >= ${exception.start} && statusCode <= ${exception.end}) {
|
|
439
|
-
error.details = ${
|
|
591
|
+
error.details = ${deserializeExpr};
|
|
440
592
|
}`;
|
|
441
593
|
} else {
|
|
442
594
|
return `if(statusCode === ${exception.start}) {
|
|
443
|
-
error.details = ${
|
|
595
|
+
error.details = ${deserializeExpr};
|
|
444
596
|
}`;
|
|
445
597
|
}
|
|
446
598
|
});
|
|
447
599
|
statements.push(stats.join("\nelse "));
|
|
448
600
|
if (defaultDeserializer) {
|
|
601
|
+
const defaultDeserializeExpr = !defaultXmlDeserializer
|
|
602
|
+
? `${defaultDeserializer}(result.body)`
|
|
603
|
+
: defaultIsXmlOnly
|
|
604
|
+
? `${defaultXmlDeserializer}(result.body)`
|
|
605
|
+
: `isXml ? ${defaultXmlDeserializer}(result.body) : ${defaultDeserializer}(result.body)`;
|
|
449
606
|
statements.push(`else {
|
|
450
|
-
error.details = ${
|
|
607
|
+
error.details = ${defaultDeserializeExpr};
|
|
451
608
|
}`);
|
|
452
609
|
}
|
|
453
610
|
statements.push("throw error;");
|
|
454
611
|
} else {
|
|
455
612
|
if (defaultDeserializer) {
|
|
456
|
-
|
|
457
|
-
|
|
613
|
+
if (defaultXmlDeserializer) {
|
|
614
|
+
if (defaultIsXmlOnly) {
|
|
615
|
+
statements.push(`const error = ${createRestErrorReference}(result);
|
|
616
|
+
error.details = ${defaultXmlDeserializer}(result.body);`);
|
|
617
|
+
} else {
|
|
618
|
+
const isXmlContentTypeRef = resolveReference(
|
|
619
|
+
XmlHelpers.isXmlContentType
|
|
620
|
+
);
|
|
621
|
+
statements.push(`const error = ${createRestErrorReference}(result);
|
|
622
|
+
const responseContentType = result.headers?.["content-type"] ?? "";
|
|
623
|
+
error.details = ${isXmlContentTypeRef}(responseContentType) ? ${defaultXmlDeserializer}(result.body) : ${defaultDeserializer}(result.body);`);
|
|
624
|
+
}
|
|
625
|
+
} else {
|
|
626
|
+
statements.push(`const error = ${createRestErrorReference}(result);
|
|
627
|
+
error.details = ${defaultDeserializer}(result.body);`);
|
|
628
|
+
}
|
|
458
629
|
statements.push("throw error;");
|
|
459
630
|
} else {
|
|
460
631
|
statements.push(`throw ${createRestErrorReference}(result);`);
|
|
@@ -497,7 +668,6 @@ function getOperationSignatureParameters(
|
|
|
497
668
|
param.methodParameterSegments[0]?.[0] === p
|
|
498
669
|
);
|
|
499
670
|
})[0]?.kind !== "cookie" &&
|
|
500
|
-
p.clientDefaultValue === undefined &&
|
|
501
671
|
!p.optional &&
|
|
502
672
|
!(
|
|
503
673
|
p.isGeneratedName &&
|
|
@@ -573,12 +743,37 @@ export function getOperationFunction(
|
|
|
573
743
|
|
|
574
744
|
// TODO: Support operation overloads
|
|
575
745
|
const response = operation.response;
|
|
746
|
+
const responseHeaders = getResponseHeaders(operation.operation.responses);
|
|
747
|
+
const hasHeaderOnlyResponse = !response.type && responseHeaders.length > 0;
|
|
748
|
+
const isResponseHeadersEnabled =
|
|
749
|
+
context.rlcOptions?.includeHeadersInResponse === true;
|
|
750
|
+
|
|
576
751
|
let returnType = { name: "", type: "void" };
|
|
577
752
|
if (response.type) {
|
|
578
753
|
const type = response.type;
|
|
754
|
+
|
|
755
|
+
// If feature flag enabled, we'll append the response headers to the operation response type.
|
|
756
|
+
if (
|
|
757
|
+
type.kind === "model" &&
|
|
758
|
+
responseHeaders.length > 0 &&
|
|
759
|
+
isResponseHeadersEnabled
|
|
760
|
+
) {
|
|
761
|
+
// Build a composite type that includes both model and additional header properties
|
|
762
|
+
returnType = {
|
|
763
|
+
name: (type as any).name ?? "",
|
|
764
|
+
type: `${buildCompositeResponseType(context, type, responseHeaders)}`
|
|
765
|
+
};
|
|
766
|
+
} else {
|
|
767
|
+
returnType = {
|
|
768
|
+
name: (type as any).name ?? "",
|
|
769
|
+
type: getTypeExpression(context, type!)
|
|
770
|
+
};
|
|
771
|
+
}
|
|
772
|
+
} else if (hasHeaderOnlyResponse && isResponseHeadersEnabled) {
|
|
773
|
+
// Here we handle returning headers when the operation return type is void
|
|
579
774
|
returnType = {
|
|
580
|
-
name:
|
|
581
|
-
type:
|
|
775
|
+
name: "",
|
|
776
|
+
type: `${buildHeaderOnlyResponseType(context, responseHeaders)}`
|
|
582
777
|
};
|
|
583
778
|
}
|
|
584
779
|
const { name, fixme = [] } = getOperationName(operation);
|
|
@@ -598,18 +793,50 @@ export function getOperationFunction(
|
|
|
598
793
|
|
|
599
794
|
const statements: string[] = [];
|
|
600
795
|
|
|
796
|
+
// Generate unique local variable names that don't conflict with parameter names
|
|
797
|
+
const paramNames = new Set(parameters.map((p) => p.name));
|
|
798
|
+
const resultVarName = generateLocallyUniqueName("result", paramNames);
|
|
799
|
+
|
|
601
800
|
const parameterList = parameters.map((p) => p.name).join(", ");
|
|
602
801
|
// Special case for binary-only bodies: use helper to call streaming methods so that Core doesn't poison the response body by
|
|
603
802
|
// doing a UTF-8 decode on the raw bytes.
|
|
604
803
|
if (response?.type?.kind === "bytes" && response.type.encode === "bytes") {
|
|
605
|
-
|
|
804
|
+
const streamableMethodVarName = generateLocallyUniqueName(
|
|
805
|
+
"streamableMethod",
|
|
806
|
+
paramNames
|
|
807
|
+
);
|
|
808
|
+
statements.push(
|
|
809
|
+
`const ${streamableMethodVarName} = _${name}Send(${parameterList});`
|
|
810
|
+
);
|
|
811
|
+
statements.push(
|
|
812
|
+
`const ${resultVarName} = await ${resolveReference(SerializationHelpers.getBinaryResponse)}(${streamableMethodVarName});`
|
|
813
|
+
);
|
|
814
|
+
} else {
|
|
606
815
|
statements.push(
|
|
607
|
-
`const
|
|
816
|
+
`const ${resultVarName} = await _${name}Send(${parameterList});`
|
|
608
817
|
);
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
// 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
|
|
821
|
+
if (responseHeaders.length > 0 && isResponseHeadersEnabled) {
|
|
822
|
+
const headersVarName = generateLocallyUniqueName("headers", paramNames);
|
|
823
|
+
statements.push(
|
|
824
|
+
`const ${headersVarName} = _${name}DeserializeHeaders(result);`
|
|
825
|
+
);
|
|
826
|
+
|
|
827
|
+
// If there is no body payload just return the headers
|
|
828
|
+
if (hasHeaderOnlyResponse) {
|
|
829
|
+
statements.push(`return {...${headersVarName} };`);
|
|
830
|
+
} else {
|
|
831
|
+
const payloadVarName = generateLocallyUniqueName("payload", paramNames);
|
|
832
|
+
statements.push(
|
|
833
|
+
`const ${payloadVarName} = await _${name}Deserialize(${resultVarName});`
|
|
834
|
+
);
|
|
835
|
+
statements.push(`return { ...${payloadVarName}, ...${headersVarName} };`);
|
|
836
|
+
}
|
|
609
837
|
} else {
|
|
610
|
-
statements.push(`
|
|
838
|
+
statements.push(`return _${name}Deserialize(${resultVarName});`);
|
|
611
839
|
}
|
|
612
|
-
statements.push(`return _${name}Deserialize(result);`);
|
|
613
840
|
|
|
614
841
|
return {
|
|
615
842
|
...functionStatement,
|
|
@@ -673,7 +900,7 @@ function getLroOnlyOperationFunction(
|
|
|
673
900
|
allowedFinalLocation.includes(lroMetadata?.finalStateVia)
|
|
674
901
|
? `resourceLocationConfig: "${lroMetadata?.finalStateVia}",`
|
|
675
902
|
: "";
|
|
676
|
-
const apiVersion = getApiVersionExpression(operation);
|
|
903
|
+
const apiVersion = getApiVersionExpression(context, operation);
|
|
677
904
|
const statements: string[] = [];
|
|
678
905
|
|
|
679
906
|
statements.push(`
|
|
@@ -716,7 +943,7 @@ function getLroAndPagingOperationFunction(
|
|
|
716
943
|
const returnType = buildLroPagingReturnType(context, operation);
|
|
717
944
|
|
|
718
945
|
// Get apiVersion expression for both LRO poller and paging options
|
|
719
|
-
const apiVersion = getApiVersionExpression(operation);
|
|
946
|
+
const apiVersion = getApiVersionExpression(context, operation);
|
|
720
947
|
|
|
721
948
|
// Build paging options from metadata
|
|
722
949
|
const pagingOptions = [
|
|
@@ -882,7 +1109,7 @@ function getPagingOnlyOperationFunction(
|
|
|
882
1109
|
// Check for nextLinkVerb from TCGC pagingMetadata (supports @Legacy.nextLinkVerb decorator)
|
|
883
1110
|
const nextLinkMethod = operation.pagingMetadata.nextLinkVerb;
|
|
884
1111
|
|
|
885
|
-
const apiVersion = getApiVersionExpression(operation);
|
|
1112
|
+
const apiVersion = getApiVersionExpression(context, operation);
|
|
886
1113
|
|
|
887
1114
|
if (itemName) {
|
|
888
1115
|
options.push(`itemName: "${itemName}"`);
|
|
@@ -1073,14 +1300,33 @@ function buildBodyParameter(
|
|
|
1073
1300
|
NameType.Parameter,
|
|
1074
1301
|
true
|
|
1075
1302
|
);
|
|
1076
|
-
|
|
1303
|
+
let bodyNameExpression = bodyParameter.optional
|
|
1077
1304
|
? `${optionalParamName}["${bodyParamName}"]`
|
|
1078
1305
|
: bodyParamName;
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
bodyParameter.optional
|
|
1083
|
-
|
|
1306
|
+
|
|
1307
|
+
// Check if body parameter has a client default value with matching type
|
|
1308
|
+
const hasClientDefault =
|
|
1309
|
+
bodyParameter.optional &&
|
|
1310
|
+
bodyParameter.clientDefaultValue !== undefined &&
|
|
1311
|
+
isDefaultValueTypeMatch(bodyParameter, bodyParameter.clientDefaultValue);
|
|
1312
|
+
|
|
1313
|
+
// Apply client default value if present for optional body parameters
|
|
1314
|
+
if (hasClientDefault) {
|
|
1315
|
+
const formattedDefault = formatDefaultValue(
|
|
1316
|
+
bodyParameter.clientDefaultValue
|
|
1317
|
+
);
|
|
1318
|
+
bodyNameExpression = `(${bodyNameExpression} ?? ${formattedDefault})`;
|
|
1319
|
+
}
|
|
1320
|
+
|
|
1321
|
+
// Only apply nullOrUndefinedPrefix if there's no client default value
|
|
1322
|
+
// because the default value already handles null/undefined cases
|
|
1323
|
+
const nullOrUndefinedPrefix = hasClientDefault
|
|
1324
|
+
? ""
|
|
1325
|
+
: getPropertySerializationPrefix(
|
|
1326
|
+
context,
|
|
1327
|
+
bodyParameter,
|
|
1328
|
+
bodyParameter.optional ? optionalParamName : undefined
|
|
1329
|
+
);
|
|
1084
1330
|
|
|
1085
1331
|
// For dual-format operations, check the contentType option at runtime
|
|
1086
1332
|
if (
|
|
@@ -1153,6 +1399,10 @@ export function getParameterMap(
|
|
|
1153
1399
|
|
|
1154
1400
|
// Special case for api-version parameters with default values
|
|
1155
1401
|
if (param.isApiVersionParam && param.clientDefaultValue) {
|
|
1402
|
+
// For multi-service, use only the default value (don't reference context.apiVersion)
|
|
1403
|
+
if (context.rlcOptions?.isMultiService) {
|
|
1404
|
+
return `"${serializedName}": "${param.clientDefaultValue}"`;
|
|
1405
|
+
}
|
|
1156
1406
|
return `"${serializedName}": ${param.onClient ? "context." : ""}${param.name} ?? "${param.clientDefaultValue}"`;
|
|
1157
1407
|
}
|
|
1158
1408
|
|
|
@@ -1226,7 +1476,7 @@ function getContentTypeValue(
|
|
|
1226
1476
|
} else {
|
|
1227
1477
|
return `contentType: ${
|
|
1228
1478
|
!param.optional
|
|
1229
|
-
?
|
|
1479
|
+
? normalizeName(param.name, NameType.Property)
|
|
1230
1480
|
: `${optionalParamName}.` + param.name + " as any"
|
|
1231
1481
|
}`;
|
|
1232
1482
|
}
|
|
@@ -1283,6 +1533,14 @@ function getOptional(
|
|
|
1283
1533
|
serializedName: string
|
|
1284
1534
|
) {
|
|
1285
1535
|
const paramName = `${param.onClient ? "context." : `${optionalParamName}?.`}${param.name}`;
|
|
1536
|
+
|
|
1537
|
+
// Apply client default value if present and type matches
|
|
1538
|
+
const defaultSuffix =
|
|
1539
|
+
param.clientDefaultValue !== undefined &&
|
|
1540
|
+
isDefaultValueTypeMatch(param, param.clientDefaultValue)
|
|
1541
|
+
? ` ?? ${formatDefaultValue(param.clientDefaultValue)}`
|
|
1542
|
+
: "";
|
|
1543
|
+
|
|
1286
1544
|
if (param.type.kind === "model") {
|
|
1287
1545
|
const propertiesStr = getRequestModelMapping(
|
|
1288
1546
|
context,
|
|
@@ -1292,7 +1550,7 @@ function getOptional(
|
|
|
1292
1550
|
const serializeContent = `{${propertiesStr.join(",")}}`;
|
|
1293
1551
|
return `"${serializedName}": ${serializeContent}`;
|
|
1294
1552
|
}
|
|
1295
|
-
|
|
1553
|
+
const serializedValue = serializeRequestValue(
|
|
1296
1554
|
context,
|
|
1297
1555
|
param.type,
|
|
1298
1556
|
paramName,
|
|
@@ -1300,7 +1558,8 @@ function getOptional(
|
|
|
1300
1558
|
getEncodeForType(param.type),
|
|
1301
1559
|
serializedName,
|
|
1302
1560
|
true
|
|
1303
|
-
)
|
|
1561
|
+
);
|
|
1562
|
+
return `"${serializedName}": ${serializedValue}${defaultSuffix}`;
|
|
1304
1563
|
}
|
|
1305
1564
|
|
|
1306
1565
|
/**
|
|
@@ -1621,7 +1880,7 @@ export function getRequestModelMapping(
|
|
|
1621
1880
|
).map(([name, value]) => `"${name}": ${value}`);
|
|
1622
1881
|
}
|
|
1623
1882
|
|
|
1624
|
-
function getPropertySerializedName(
|
|
1883
|
+
export function getPropertySerializedName(
|
|
1625
1884
|
property: SdkHttpParameter | SdkModelPropertyType
|
|
1626
1885
|
) {
|
|
1627
1886
|
return (
|
|
@@ -1835,6 +2094,77 @@ export function serializeRequestValue(
|
|
|
1835
2094
|
}
|
|
1836
2095
|
}
|
|
1837
2096
|
|
|
2097
|
+
/**
|
|
2098
|
+
* 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.
|
|
2099
|
+
* 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.
|
|
2100
|
+
*/
|
|
2101
|
+
export function deserializeResponseHeadersValue(
|
|
2102
|
+
context: SdkContext,
|
|
2103
|
+
type: SdkType,
|
|
2104
|
+
restValue: string,
|
|
2105
|
+
required: boolean,
|
|
2106
|
+
format?: string,
|
|
2107
|
+
recursionDepth: number = 0
|
|
2108
|
+
) {
|
|
2109
|
+
const nullOrUndefinedPrefix =
|
|
2110
|
+
isTypeNullable(type) || getOptionalForType(type) || !required
|
|
2111
|
+
? `${restValue} === undefined || ${restValue} === null ? ${restValue}: `
|
|
2112
|
+
: "";
|
|
2113
|
+
|
|
2114
|
+
switch (type.kind) {
|
|
2115
|
+
case "constant":
|
|
2116
|
+
return `${restValue} as any`;
|
|
2117
|
+
case "boolean":
|
|
2118
|
+
return `${nullOrUndefinedPrefix} ${restValue}.trim().toLowerCase() === "true"`;
|
|
2119
|
+
case "int16":
|
|
2120
|
+
case "int32":
|
|
2121
|
+
case "int64":
|
|
2122
|
+
case "uint16":
|
|
2123
|
+
case "uint32":
|
|
2124
|
+
case "uint64":
|
|
2125
|
+
case "float":
|
|
2126
|
+
case "decimal":
|
|
2127
|
+
case "decimal128":
|
|
2128
|
+
case "float32":
|
|
2129
|
+
case "float64":
|
|
2130
|
+
case "int8":
|
|
2131
|
+
case "integer":
|
|
2132
|
+
case "numeric":
|
|
2133
|
+
case "safeint":
|
|
2134
|
+
case "uint8":
|
|
2135
|
+
return `${nullOrUndefinedPrefix} Number(${restValue})`;
|
|
2136
|
+
case "enum":
|
|
2137
|
+
if (isNormalUnion(type)) {
|
|
2138
|
+
return `${restValue}`;
|
|
2139
|
+
} else if (isSpecialHandledUnion(type)) {
|
|
2140
|
+
const deserializeFunctionName = type
|
|
2141
|
+
? buildModelDeserializer(context, getNullableValidType(type), {
|
|
2142
|
+
nameOnly: true,
|
|
2143
|
+
skipDiscriminatedUnionSuffix: false
|
|
2144
|
+
})
|
|
2145
|
+
: undefined;
|
|
2146
|
+
if (deserializeFunctionName) {
|
|
2147
|
+
return `${deserializeFunctionName}(${restValue})`;
|
|
2148
|
+
} else {
|
|
2149
|
+
return `${restValue} as any`;
|
|
2150
|
+
}
|
|
2151
|
+
} else {
|
|
2152
|
+
return `${restValue} as any`;
|
|
2153
|
+
}
|
|
2154
|
+
default: {
|
|
2155
|
+
const val = deserializeResponseValue(
|
|
2156
|
+
context,
|
|
2157
|
+
type,
|
|
2158
|
+
restValue,
|
|
2159
|
+
true,
|
|
2160
|
+
format,
|
|
2161
|
+
recursionDepth
|
|
2162
|
+
);
|
|
2163
|
+
return `${nullOrUndefinedPrefix} ${val}`;
|
|
2164
|
+
}
|
|
2165
|
+
}
|
|
2166
|
+
}
|
|
2167
|
+
|
|
1838
2168
|
/**
|
|
1839
2169
|
* This function helps converting strings into JS complex types recursively.
|
|
1840
2170
|
* We need to drill down into Array elements to make sure that the element type is
|
|
@@ -2042,12 +2372,59 @@ export function getAllAncestors(type: SdkType): SdkType[] {
|
|
|
2042
2372
|
return ancestors;
|
|
2043
2373
|
}
|
|
2044
2374
|
|
|
2375
|
+
/**
|
|
2376
|
+
* Checks if a clientDefaultValue type matches the parameter type.
|
|
2377
|
+
* Returns true if the default value type is compatible with the parameter type.
|
|
2378
|
+
*/
|
|
2379
|
+
function isDefaultValueTypeMatch(
|
|
2380
|
+
param: SdkHttpParameter | SdkBodyParameter,
|
|
2381
|
+
defaultValue: unknown
|
|
2382
|
+
): boolean {
|
|
2383
|
+
const defaultType = typeof defaultValue;
|
|
2384
|
+
const paramType = param.type;
|
|
2385
|
+
|
|
2386
|
+
// Map JavaScript types to TypeSpec types
|
|
2387
|
+
if (defaultType === "string") {
|
|
2388
|
+
return paramType.kind === "string" || paramType.kind === "enum";
|
|
2389
|
+
}
|
|
2390
|
+
if (defaultType === "number") {
|
|
2391
|
+
return (
|
|
2392
|
+
paramType.kind === "int32" ||
|
|
2393
|
+
paramType.kind === "int64" ||
|
|
2394
|
+
paramType.kind === "float32" ||
|
|
2395
|
+
paramType.kind === "float64" ||
|
|
2396
|
+
paramType.kind === "numeric" ||
|
|
2397
|
+
paramType.kind === "integer" ||
|
|
2398
|
+
paramType.kind === "float" ||
|
|
2399
|
+
paramType.kind === "decimal"
|
|
2400
|
+
);
|
|
2401
|
+
}
|
|
2402
|
+
if (defaultType === "boolean") {
|
|
2403
|
+
return paramType.kind === "boolean";
|
|
2404
|
+
}
|
|
2405
|
+
|
|
2406
|
+
// For other types, don't apply the default
|
|
2407
|
+
return false;
|
|
2408
|
+
}
|
|
2409
|
+
|
|
2410
|
+
/**
|
|
2411
|
+
* Formats a default value for code generation.
|
|
2412
|
+
* Strings are wrapped in quotes, other values are used as-is.
|
|
2413
|
+
*/
|
|
2414
|
+
function formatDefaultValue(defaultValue: unknown): string {
|
|
2415
|
+
if (typeof defaultValue === "string") {
|
|
2416
|
+
return `"${defaultValue}"`;
|
|
2417
|
+
}
|
|
2418
|
+
return String(defaultValue);
|
|
2419
|
+
}
|
|
2420
|
+
|
|
2045
2421
|
export function getPropertySerializationPrefix(
|
|
2046
2422
|
context: SdkContext,
|
|
2047
2423
|
property: SdkHttpParameter | SdkModelPropertyType,
|
|
2048
2424
|
propertyPath?: string
|
|
2049
2425
|
) {
|
|
2050
2426
|
const propertyFullName = getPropertyFullName(context, property, propertyPath);
|
|
2427
|
+
|
|
2051
2428
|
if (property.optional || isTypeNullable(property.type)) {
|
|
2052
2429
|
return `!${propertyFullName}? ${propertyFullName}:`;
|
|
2053
2430
|
}
|
|
@@ -2073,6 +2450,7 @@ export function getPropertyFullName(
|
|
|
2073
2450
|
} else if (propertyPath) {
|
|
2074
2451
|
fullName = `${propertyPath}["${normalizedPropertyName}"]`;
|
|
2075
2452
|
}
|
|
2453
|
+
|
|
2076
2454
|
return fullName;
|
|
2077
2455
|
}
|
|
2078
2456
|
|
|
@@ -2102,10 +2480,12 @@ export function getExpectedStatuses(operation: ServiceOperation): string {
|
|
|
2102
2480
|
|
|
2103
2481
|
/**
|
|
2104
2482
|
* Gets the apiVersion expression with default value fallback for query parameters.
|
|
2483
|
+
* @param dpgContext - The SDK context
|
|
2105
2484
|
* @param operation - The operation to get the apiVersion parameter from
|
|
2106
2485
|
* @returns The apiVersion expression string, or undefined if no apiVersion query param exists
|
|
2107
2486
|
*/
|
|
2108
2487
|
function getApiVersionExpression(
|
|
2488
|
+
dpgContext: SdkContext,
|
|
2109
2489
|
operation: ServiceOperation
|
|
2110
2490
|
): string | undefined {
|
|
2111
2491
|
const queryApiVersionParam = operation.operation.parameters.find(
|
|
@@ -2114,9 +2494,122 @@ function getApiVersionExpression(
|
|
|
2114
2494
|
if (!queryApiVersionParam) {
|
|
2115
2495
|
return undefined;
|
|
2116
2496
|
}
|
|
2497
|
+
// For multi-service, use only the default value (don't reference context.apiVersion)
|
|
2498
|
+
if (dpgContext.rlcOptions?.isMultiService) {
|
|
2499
|
+
return queryApiVersionParam.clientDefaultValue
|
|
2500
|
+
? `"${queryApiVersionParam.clientDefaultValue}"`
|
|
2501
|
+
: undefined;
|
|
2502
|
+
}
|
|
2117
2503
|
const paramAccess = `${queryApiVersionParam.onClient ? "context." : ""}${queryApiVersionParam.name}`;
|
|
2118
2504
|
const defaultValueSuffix = queryApiVersionParam.clientDefaultValue
|
|
2119
2505
|
? ` ?? "${queryApiVersionParam.clientDefaultValue}"`
|
|
2120
2506
|
: "";
|
|
2121
2507
|
return `${paramAccess}${defaultValueSuffix}`;
|
|
2122
2508
|
}
|
|
2509
|
+
|
|
2510
|
+
/**
|
|
2511
|
+
* Extracts and deduplicates all response headers from operation responses.
|
|
2512
|
+
* @param responses - The operation responses
|
|
2513
|
+
* @returns Array of unique response headers
|
|
2514
|
+
*/
|
|
2515
|
+
export function getResponseHeaders(
|
|
2516
|
+
responses: SdkHttpOperation["responses"]
|
|
2517
|
+
): SdkServiceResponseHeader[] {
|
|
2518
|
+
const headerMap = new Map<string, SdkServiceResponseHeader>();
|
|
2519
|
+
for (const response of responses ?? []) {
|
|
2520
|
+
for (const header of response.headers ?? []) {
|
|
2521
|
+
const key = header.serializedName ?? header.name;
|
|
2522
|
+
if (!headerMap.has(key)) {
|
|
2523
|
+
headerMap.set(key, header);
|
|
2524
|
+
}
|
|
2525
|
+
}
|
|
2526
|
+
}
|
|
2527
|
+
return Array.from(headerMap.values());
|
|
2528
|
+
}
|
|
2529
|
+
|
|
2530
|
+
/**
|
|
2531
|
+
* Builds a composite return type for operations that return both a model and additional headers.
|
|
2532
|
+
* Combines model properties and header properties into an inline object type.
|
|
2533
|
+
* @param context - The SDK context
|
|
2534
|
+
* @param modelType - The model type
|
|
2535
|
+
* @param headers - The response headers that are NOT in the model
|
|
2536
|
+
* @returns The composite type expression as a string (e.g., "{ name: string; email: string; requestId: string }")
|
|
2537
|
+
*/
|
|
2538
|
+
function buildCompositeResponseType(
|
|
2539
|
+
context: SdkContext,
|
|
2540
|
+
modelType: SdkModelType,
|
|
2541
|
+
headers: SdkServiceResponseHeader[]
|
|
2542
|
+
): string {
|
|
2543
|
+
const allParents = getAllAncestors(modelType);
|
|
2544
|
+
const modelProps: (SdkModelPropertyType | SdkServiceResponseHeader)[] =
|
|
2545
|
+
getAllProperties(context, modelType, allParents);
|
|
2546
|
+
|
|
2547
|
+
// Collect header property names already in the model to avoid duplicates
|
|
2548
|
+
const modelHeaderNames = new Set<string>();
|
|
2549
|
+
for (const property of modelProps) {
|
|
2550
|
+
if (isHeader(context.program, property.__raw!)) {
|
|
2551
|
+
modelHeaderNames.add(property.name.toLowerCase());
|
|
2552
|
+
}
|
|
2553
|
+
}
|
|
2554
|
+
|
|
2555
|
+
// Add only additional host response header properties not already in model
|
|
2556
|
+
for (const header of headers) {
|
|
2557
|
+
if (modelHeaderNames.has(header.name.toLowerCase())) {
|
|
2558
|
+
continue;
|
|
2559
|
+
}
|
|
2560
|
+
modelProps.push(header);
|
|
2561
|
+
}
|
|
2562
|
+
|
|
2563
|
+
return emitInlineModel(context, modelProps);
|
|
2564
|
+
}
|
|
2565
|
+
|
|
2566
|
+
/**
|
|
2567
|
+
* Builds an inline type string for header-only responses.
|
|
2568
|
+
* @param context - The SDK context
|
|
2569
|
+
* @param headers - The response headers
|
|
2570
|
+
* @returns The inline type expression as a string (e.g., "{ requestId: string; optionalHeader?: string }")
|
|
2571
|
+
*/
|
|
2572
|
+
function buildHeaderOnlyResponseType(
|
|
2573
|
+
context: SdkContext,
|
|
2574
|
+
headers: SdkServiceResponseHeader[]
|
|
2575
|
+
): string {
|
|
2576
|
+
const properties: string[] = [];
|
|
2577
|
+
|
|
2578
|
+
for (const header of headers) {
|
|
2579
|
+
const headerName = normalizeModelPropertyName(context, header);
|
|
2580
|
+
const headerType = getTypeExpression(context, header.type);
|
|
2581
|
+
const isOptional = header.optional ? "?" : "";
|
|
2582
|
+
properties.push(`${headerName}${isOptional}: ${headerType}`);
|
|
2583
|
+
}
|
|
2584
|
+
|
|
2585
|
+
return `{ ${properties.join("; ")} }`;
|
|
2586
|
+
}
|
|
2587
|
+
|
|
2588
|
+
/**
|
|
2589
|
+
* Builds the object literal expression for a header-only response.
|
|
2590
|
+
* Handles type conversions for headers (string to boolean, Date, number, Uint8Array).
|
|
2591
|
+
* @param operation - The service operation
|
|
2592
|
+
* @param headers - The response headers
|
|
2593
|
+
* @returns JavaScript expression string for the header-only response object
|
|
2594
|
+
*/
|
|
2595
|
+
function buildHeaderOnlyResponseValue(
|
|
2596
|
+
context: SdkContext,
|
|
2597
|
+
headers: SdkServiceResponseHeader[]
|
|
2598
|
+
): string {
|
|
2599
|
+
const props = headers.map((header) => {
|
|
2600
|
+
const headerName = (header.serializedName ?? header.name).toLowerCase();
|
|
2601
|
+
const key = normalizeModelPropertyName(context, header);
|
|
2602
|
+
const value = deserializeResponseHeadersValue(
|
|
2603
|
+
context,
|
|
2604
|
+
header.type,
|
|
2605
|
+
`result.headers[${JSON.stringify(headerName)}]`,
|
|
2606
|
+
!header.optional,
|
|
2607
|
+
getEncodeForType(header.type),
|
|
2608
|
+
0
|
|
2609
|
+
);
|
|
2610
|
+
|
|
2611
|
+
return `${key}: ${value}`;
|
|
2612
|
+
});
|
|
2613
|
+
|
|
2614
|
+
return `{ ${props.join(", ")} }`;
|
|
2615
|
+
}
|