@azure-tools/typespec-ts 0.51.1 → 0.52.0
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 +7 -0
- package/dist/src/modular/buildClassicalClient.d.ts.map +1 -1
- package/dist/src/modular/buildClassicalClient.js +1 -0
- package/dist/src/modular/buildClassicalClient.js.map +1 -1
- package/dist/src/modular/emitModels.d.ts.map +1 -1
- package/dist/src/modular/emitModels.js +28 -2
- package/dist/src/modular/emitModels.js.map +1 -1
- package/dist/src/modular/helpers/operationHelpers.d.ts +1 -1
- package/dist/src/modular/helpers/operationHelpers.d.ts.map +1 -1
- package/dist/src/modular/helpers/operationHelpers.js +156 -78
- package/dist/src/modular/helpers/operationHelpers.js.map +1 -1
- package/dist/src/modular/serialization/buildSerializerFunction.js +2 -7
- package/dist/src/modular/serialization/buildSerializerFunction.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +14 -21
- package/src/modular/buildClassicalClient.ts +1 -0
- package/src/modular/emitModels.ts +34 -2
- package/src/modular/helpers/operationHelpers.ts +182 -93
- package/src/modular/serialization/buildSerializerFunction.ts +2 -6
|
@@ -22,6 +22,7 @@ import { getClientOptions, isHttpMetadata, isReadOnly } from "@azure-tools/types
|
|
|
22
22
|
import { isHeader, isMetadata } from "@typespec/http";
|
|
23
23
|
import { useContext } from "../../contextManager.js";
|
|
24
24
|
import { getHeaderClientOptions, getRestErrorCodeHeader } from "./clientOptionHelpers.js";
|
|
25
|
+
import { getClientParameterName } from "./clientHelpers.js";
|
|
25
26
|
import { isExtensibleEnum } from "../type-expressions/get-enum-expression.js";
|
|
26
27
|
import { emitInlineModel } from "../type-expressions/get-model-expression.js";
|
|
27
28
|
/**
|
|
@@ -96,7 +97,16 @@ export function getDeserializePrivateFunction(context, method) {
|
|
|
96
97
|
const restResponse = operation.operation.responses[0];
|
|
97
98
|
let returnType;
|
|
98
99
|
if (isLroOnly || isLroAndPaging) {
|
|
99
|
-
|
|
100
|
+
if (isLroOnly && shouldWrap) {
|
|
101
|
+
// For LRO-only operations with non-model final result, wrap in a response type alias
|
|
102
|
+
returnType = {
|
|
103
|
+
name: getOperationResponseTypeName(method),
|
|
104
|
+
type: resolveReference(refkey(operation, "response"))
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
returnType = buildLroReturnType(context, operation);
|
|
109
|
+
}
|
|
100
110
|
}
|
|
101
111
|
else if (isPagingOnly && (restResponse === null || restResponse === void 0 ? void 0 : restResponse.type)) {
|
|
102
112
|
// For paging operations, use the full response model (e.g., _OperationListResult)
|
|
@@ -237,7 +247,7 @@ export function getDeserializePrivateFunction(context, method) {
|
|
|
237
247
|
nameOnly: true,
|
|
238
248
|
skipDiscriminatedUnionSuffix: false
|
|
239
249
|
});
|
|
240
|
-
// Handle wrap-non-model-return for non-LRO, non-paging operations
|
|
250
|
+
// Handle wrap-non-model-return for non-LRO, non-paging and LRO-only operations
|
|
241
251
|
if (shouldWrap) {
|
|
242
252
|
if (isBinary) {
|
|
243
253
|
// Binary wrap: getBinaryStream already resolved the stream,
|
|
@@ -247,8 +257,9 @@ export function getDeserializePrivateFunction(context, method) {
|
|
|
247
257
|
}
|
|
248
258
|
else {
|
|
249
259
|
// Non-model response: wrap with body property
|
|
250
|
-
// Generate the appropriate deserialization for the body value
|
|
251
|
-
|
|
260
|
+
// Generate the appropriate deserialization for the body value.
|
|
261
|
+
// For LRO operations, deserializedRoot may include the sub-path (e.g. result.body.someProperty).
|
|
262
|
+
const bodyValue = deserializeResponseValue(context, deserializedType, deserializedRoot, true, getEncodeForType(deserializedType));
|
|
252
263
|
statements.push(`return { body: ${bodyValue} };`);
|
|
253
264
|
}
|
|
254
265
|
return {
|
|
@@ -829,6 +840,15 @@ function getLroOnlyOperationFunction(context, method, clientType, optionalParamN
|
|
|
829
840
|
const { name, fixme = [] } = getOperationName(operation);
|
|
830
841
|
const pollerLikeReference = resolveReference(AzurePollingDependencies.PollerLike);
|
|
831
842
|
const operationStateReference = resolveReference(AzurePollingDependencies.OperationState);
|
|
843
|
+
// When wrap-non-model-return is enabled and the LRO final result is a non-model type,
|
|
844
|
+
// use the wrapper response type (e.g. GetIkeSasResponse) instead of the raw type (e.g. string).
|
|
845
|
+
const { shouldWrap } = checkWrapNonModelReturn(context, operation);
|
|
846
|
+
const effectiveReturnTypeStr = shouldWrap
|
|
847
|
+
? resolveReference(refkey(operation, "response"))
|
|
848
|
+
: returnType.type;
|
|
849
|
+
const effectiveReturnTypeName = shouldWrap
|
|
850
|
+
? getOperationResponseTypeName(method)
|
|
851
|
+
: returnType.type;
|
|
832
852
|
const functionStatement = {
|
|
833
853
|
kind: StructureKind.Function,
|
|
834
854
|
docs: [
|
|
@@ -840,9 +860,9 @@ function getLroOnlyOperationFunction(context, method, clientType, optionalParamN
|
|
|
840
860
|
name,
|
|
841
861
|
propertyName: normalizeName(operation.name, NameType.Property),
|
|
842
862
|
isLro: true,
|
|
843
|
-
lroFinalReturnType:
|
|
863
|
+
lroFinalReturnType: effectiveReturnTypeName,
|
|
844
864
|
parameters,
|
|
845
|
-
returnType: `${pollerLikeReference}<${operationStateReference}<${
|
|
865
|
+
returnType: `${pollerLikeReference}<${operationStateReference}<${effectiveReturnTypeStr}>, ${effectiveReturnTypeStr}>`
|
|
846
866
|
};
|
|
847
867
|
const getLongRunningPollerReference = resolveReference(PollingHelpers.GetLongRunningPoller);
|
|
848
868
|
const lroMetadata = operation.kind === "lro" || operation.kind === "lropaging"
|
|
@@ -870,7 +890,7 @@ function getLroOnlyOperationFunction(context, method, clientType, optionalParamN
|
|
|
870
890
|
.join(", ")}),
|
|
871
891
|
${resourceLocationConfig}
|
|
872
892
|
${apiVersion ? `apiVersion: ${apiVersion}` : ""}
|
|
873
|
-
}) as ${pollerLikeReference}<${operationStateReference}<${
|
|
893
|
+
}) as ${pollerLikeReference}<${operationStateReference}<${effectiveReturnTypeStr}>, ${effectiveReturnTypeStr}>;
|
|
874
894
|
`);
|
|
875
895
|
return {
|
|
876
896
|
...functionStatement,
|
|
@@ -1082,9 +1102,11 @@ function getHeaderAndBodyParameters(dpgContext, operation, optionalParamName = "
|
|
|
1082
1102
|
// Check if this parameter still exists in the corresponding method params (after override)
|
|
1083
1103
|
if (param.methodParameterSegments &&
|
|
1084
1104
|
param.methodParameterSegments.length > 0) {
|
|
1105
|
+
const paramAccessor = getParamAccessor(param, optionalParamName);
|
|
1085
1106
|
parametersImplementation[param.kind].push({
|
|
1086
|
-
paramMap: getParameterMap(dpgContext, param,
|
|
1087
|
-
param
|
|
1107
|
+
paramMap: getParameterMap(dpgContext, param, paramAccessor),
|
|
1108
|
+
param,
|
|
1109
|
+
paramAccessor
|
|
1088
1110
|
});
|
|
1089
1111
|
}
|
|
1090
1112
|
}
|
|
@@ -1095,7 +1117,7 @@ function getHeaderAndBodyParameters(dpgContext, operation, optionalParamName = "
|
|
|
1095
1117
|
}
|
|
1096
1118
|
if (parametersImplementation.header.length) {
|
|
1097
1119
|
paramStr = `${paramStr}\nheaders: {${parametersImplementation.header
|
|
1098
|
-
.map((i) => buildHeaderParameter(dpgContext.program, i.paramMap, i.param,
|
|
1120
|
+
.map((i) => buildHeaderParameter(dpgContext.program, i.paramMap, i.param, i.paramAccessor))
|
|
1099
1121
|
.join(",\n")}, ...${optionalParamName}.requestOptions?.headers },`;
|
|
1100
1122
|
}
|
|
1101
1123
|
if (operation.operation.bodyParam === undefined &&
|
|
@@ -1110,8 +1132,7 @@ function getHeaderAndBodyParameters(dpgContext, operation, optionalParamName = "
|
|
|
1110
1132
|
return paramStr;
|
|
1111
1133
|
}
|
|
1112
1134
|
// Specially handle the type for headers because we only allow string/number/boolean values
|
|
1113
|
-
function buildHeaderParameter(program, paramMap, param,
|
|
1114
|
-
const paramName = param.name;
|
|
1135
|
+
function buildHeaderParameter(program, paramMap, param, paramAccessor) {
|
|
1115
1136
|
const effectiveOptional = getEffectiveOptional(param);
|
|
1116
1137
|
if (!effectiveOptional && isTypeNullable(param.type) === true) {
|
|
1117
1138
|
reportDiagnostic(program, {
|
|
@@ -1122,10 +1143,10 @@ function buildHeaderParameter(program, paramMap, param, optionalParamName = "opt
|
|
|
1122
1143
|
}
|
|
1123
1144
|
const conditions = [];
|
|
1124
1145
|
if (effectiveOptional) {
|
|
1125
|
-
conditions.push(`${
|
|
1146
|
+
conditions.push(`${paramAccessor} !== undefined`);
|
|
1126
1147
|
}
|
|
1127
1148
|
if (isTypeNullable(param.type) === true) {
|
|
1128
|
-
conditions.push(`${
|
|
1149
|
+
conditions.push(`${paramAccessor} !== null`);
|
|
1129
1150
|
}
|
|
1130
1151
|
return conditions.length > 0
|
|
1131
1152
|
? `...(${conditions.join(" && ")} ? {${paramMap}} : {})`
|
|
@@ -1214,7 +1235,7 @@ function getEncodingFormat(type) {
|
|
|
1214
1235
|
/**
|
|
1215
1236
|
* This function helps with renames, translating client names to rest api names
|
|
1216
1237
|
*/
|
|
1217
|
-
export function getParameterMap(context, param,
|
|
1238
|
+
export function getParameterMap(context, param, paramAccessor) {
|
|
1218
1239
|
var _a;
|
|
1219
1240
|
// Use lowercase for header names since HTTP headers are case-insensitive
|
|
1220
1241
|
const serializedName = param.kind === "header"
|
|
@@ -1232,14 +1253,14 @@ export function getParameterMap(context, param, optionalParamName = "options") {
|
|
|
1232
1253
|
return `"${serializedName}": ${param.onClient ? "context." : ""}${param.name} ?? "${param.clientDefaultValue}"`;
|
|
1233
1254
|
}
|
|
1234
1255
|
if (hasCollectionFormatInfo(param.kind, param.collectionFormat)) {
|
|
1235
|
-
return getCollectionFormatForParam(context, param,
|
|
1256
|
+
return getCollectionFormatForParam(context, param, paramAccessor, serializedName);
|
|
1236
1257
|
}
|
|
1237
1258
|
// if the parameter or property is optional, we don't need to handle the default value
|
|
1238
1259
|
if (isOptional(param)) {
|
|
1239
|
-
return getOptional(context, param,
|
|
1260
|
+
return getOptional(context, param, serializedName, paramAccessor);
|
|
1240
1261
|
}
|
|
1241
1262
|
if (isRequired(param)) {
|
|
1242
|
-
return getRequired(context, param, serializedName);
|
|
1263
|
+
return getRequired(context, param, serializedName, paramAccessor);
|
|
1243
1264
|
}
|
|
1244
1265
|
reportDiagnostic(context.program, {
|
|
1245
1266
|
code: "unsupported-parameter-type",
|
|
@@ -1252,9 +1273,9 @@ export function getParameterMap(context, param, optionalParamName = "options") {
|
|
|
1252
1273
|
// Return a fallback value to allow the emitter to continue
|
|
1253
1274
|
return `"${param.name}": undefined`;
|
|
1254
1275
|
}
|
|
1255
|
-
function getCollectionFormatForParam(context, param,
|
|
1276
|
+
function getCollectionFormatForParam(context, param, paramAccessor, serializedName) {
|
|
1256
1277
|
const format = param.collectionFormat;
|
|
1257
|
-
return `"${serializedName}": ${serializeRequestValue(context, param.type,
|
|
1278
|
+
return `"${serializedName}": ${serializeRequestValue(context, param.type, paramAccessor, !param.optional, format, serializedName, true)}`;
|
|
1258
1279
|
}
|
|
1259
1280
|
function isContentType(param) {
|
|
1260
1281
|
return (param.kind === "header" &&
|
|
@@ -1302,13 +1323,12 @@ function getEffectiveOptional(param) {
|
|
|
1302
1323
|
function isRequired(param) {
|
|
1303
1324
|
return !getEffectiveOptional(param);
|
|
1304
1325
|
}
|
|
1305
|
-
function getRequired(context, param, serializedName) {
|
|
1306
|
-
const clientValue = `${param.onClient ? "context." : ""}${param.name}`;
|
|
1326
|
+
function getRequired(context, param, serializedName, paramAccessor) {
|
|
1307
1327
|
if (param.type.kind === "model") {
|
|
1308
|
-
const propertiesStr = getRequestModelMapping(context, { ...param.type, optional: param.optional },
|
|
1328
|
+
const propertiesStr = getRequestModelMapping(context, { ...param.type, optional: param.optional }, paramAccessor);
|
|
1309
1329
|
return `"${serializedName}": { ${propertiesStr.join(",")} }`;
|
|
1310
1330
|
}
|
|
1311
|
-
return `"${serializedName}": ${serializeRequestValue(context, param.type,
|
|
1331
|
+
return `"${serializedName}": ${serializeRequestValue(context, param.type, paramAccessor, true, getEncodeForType(param.type), serializedName, true)}`;
|
|
1312
1332
|
}
|
|
1313
1333
|
function getConstantValue(param) {
|
|
1314
1334
|
if (typeof param.value === "string") {
|
|
@@ -1322,19 +1342,18 @@ function isConstant(param) {
|
|
|
1322
1342
|
function isOptional(param) {
|
|
1323
1343
|
return getEffectiveOptional(param);
|
|
1324
1344
|
}
|
|
1325
|
-
function getOptional(context, param,
|
|
1326
|
-
const paramName = `${param.onClient ? "context." : `${optionalParamName}?.`}${param.name}`;
|
|
1345
|
+
function getOptional(context, param, serializedName, paramAccessor) {
|
|
1327
1346
|
// Apply client default value if present and type matches
|
|
1328
1347
|
const defaultSuffix = param.clientDefaultValue !== undefined &&
|
|
1329
1348
|
isDefaultValueTypeMatch(param, param.clientDefaultValue)
|
|
1330
1349
|
? ` ?? ${formatDefaultValue(param.clientDefaultValue)}`
|
|
1331
1350
|
: "";
|
|
1332
1351
|
if (param.type.kind === "model") {
|
|
1333
|
-
const propertiesStr = getRequestModelMapping(context, { ...param.type, optional: param.optional },
|
|
1352
|
+
const propertiesStr = getRequestModelMapping(context, { ...param.type, optional: param.optional }, paramAccessor + "?.");
|
|
1334
1353
|
const serializeContent = `{${propertiesStr.join(",")}}`;
|
|
1335
1354
|
return `"${serializedName}": ${serializeContent}`;
|
|
1336
1355
|
}
|
|
1337
|
-
const serializedValue = serializeRequestValue(context, param.type,
|
|
1356
|
+
const serializedValue = serializeRequestValue(context, param.type, paramAccessor, false, getEncodeForType(param.type), serializedName, true);
|
|
1338
1357
|
return `"${serializedName}": ${serializedValue}${defaultSuffix}`;
|
|
1339
1358
|
}
|
|
1340
1359
|
/**
|
|
@@ -1368,7 +1387,7 @@ function getPathParameters(operation, optionalParamName = "options") {
|
|
|
1368
1387
|
if (param.kind === "path") {
|
|
1369
1388
|
const methodParam = (_a = param.methodParameterSegments[0]) === null || _a === void 0 ? void 0 : _a[0];
|
|
1370
1389
|
if (methodParam) {
|
|
1371
|
-
pathParams.push(`"${param.serializedName}": ${getPathParamExpr(
|
|
1390
|
+
pathParams.push(`"${param.serializedName}": ${getPathParamExpr(param, getDefaultValue(param), optionalParamName)}`);
|
|
1372
1391
|
}
|
|
1373
1392
|
}
|
|
1374
1393
|
}
|
|
@@ -1390,13 +1409,14 @@ function getQueryParameters(dpgContext, operation) {
|
|
|
1390
1409
|
// Check if this parameter still exists in the corresponding method params (after override)
|
|
1391
1410
|
if (param.methodParameterSegments &&
|
|
1392
1411
|
param.methodParameterSegments.length > 0) {
|
|
1412
|
+
const paramAccessor = getParamAccessor(param);
|
|
1393
1413
|
parametersImplementation[param.kind].push({
|
|
1394
1414
|
paramMap: getParameterMap(dpgContext, {
|
|
1395
1415
|
...param,
|
|
1396
1416
|
// TODO: remember to remove this hack once compiler gives us a name
|
|
1397
1417
|
// https://github.com/microsoft/typespec/issues/6743
|
|
1398
1418
|
serializedName: getUriTemplateQueryParamName(param.serializedName)
|
|
1399
|
-
}),
|
|
1419
|
+
}, paramAccessor),
|
|
1400
1420
|
param
|
|
1401
1421
|
});
|
|
1402
1422
|
}
|
|
@@ -1413,15 +1433,69 @@ function escapeUriTemplateParamName(name) {
|
|
|
1413
1433
|
return "%" + c.charCodeAt(0).toString(16).toUpperCase();
|
|
1414
1434
|
});
|
|
1415
1435
|
}
|
|
1436
|
+
/**
|
|
1437
|
+
* Returns the parameter expression matching the operation signature for an HTTP parameter.
|
|
1438
|
+
* 1. Client-level parameter (`param.onClient`): returns `context.<paramName>`.
|
|
1439
|
+
* 2. Method-level parameter with `methodParameterSegments`: returns the expression
|
|
1440
|
+
* built from those segments (e.g. `options?.ocpDate`, `body.nested`).
|
|
1441
|
+
* 3. Fallback: returns the parameter name directly, with optional chaining if optional.
|
|
1442
|
+
*/
|
|
1443
|
+
function getParamAccessor(param, optionalParamName = "options") {
|
|
1444
|
+
const methodParamExpr = getMethodParamExpr(param, optionalParamName);
|
|
1445
|
+
const clientPrefix = "context.";
|
|
1446
|
+
if (methodParamExpr) {
|
|
1447
|
+
return param.onClient
|
|
1448
|
+
? `${clientPrefix}${methodParamExpr}`
|
|
1449
|
+
: methodParamExpr;
|
|
1450
|
+
}
|
|
1451
|
+
if (param.onClient) {
|
|
1452
|
+
return `${clientPrefix}${getClientParameterName(param)}`;
|
|
1453
|
+
}
|
|
1454
|
+
if (getEffectiveOptional(param)) {
|
|
1455
|
+
return `${optionalParamName}?.${param.name}`;
|
|
1456
|
+
}
|
|
1457
|
+
return param.name;
|
|
1458
|
+
}
|
|
1459
|
+
/**
|
|
1460
|
+
* Builds a property accessor expression from the param's `methodParameterSegments`.
|
|
1461
|
+
* Each segment represents a level of property access (e.g. `options?.nested.value`).
|
|
1462
|
+
* Returns `undefined` when no segments are available, so the caller can fall back.
|
|
1463
|
+
*/
|
|
1464
|
+
function getMethodParamExpr(param, optionalParamName = "options") {
|
|
1465
|
+
const segments = param.methodParameterSegments;
|
|
1466
|
+
if (segments.length === 0) {
|
|
1467
|
+
return undefined;
|
|
1468
|
+
}
|
|
1469
|
+
const path = segments[0];
|
|
1470
|
+
if (!path || path.length < 1) {
|
|
1471
|
+
return undefined;
|
|
1472
|
+
}
|
|
1473
|
+
const parts = [];
|
|
1474
|
+
for (let i = 0; i < path.length; i++) {
|
|
1475
|
+
const segment = path[i];
|
|
1476
|
+
if (i === 0) {
|
|
1477
|
+
// Normalize names for client-level segments to match the context interface property names
|
|
1478
|
+
const segmentName = segment.onClient
|
|
1479
|
+
? getClientParameterName(segment)
|
|
1480
|
+
: segment.name;
|
|
1481
|
+
if (segment.optional && !segment.onClient) {
|
|
1482
|
+
// If the first segment is optional and not on the client, we need to start with the optionalParamName
|
|
1483
|
+
parts.push(`${optionalParamName}?.`);
|
|
1484
|
+
}
|
|
1485
|
+
parts.push(segmentName);
|
|
1486
|
+
}
|
|
1487
|
+
else {
|
|
1488
|
+
const needsOptionalChain = path[i - 1].optional;
|
|
1489
|
+
parts.push(`${needsOptionalChain ? "?." : "."}${segment.name}`);
|
|
1490
|
+
}
|
|
1491
|
+
}
|
|
1492
|
+
return parts.join("");
|
|
1493
|
+
}
|
|
1416
1494
|
function getPathParamExpr(param, defaultValue, optionalParamName = "options") {
|
|
1417
1495
|
if (isConstant(param.type)) {
|
|
1418
1496
|
return getConstantValue(param.type);
|
|
1419
1497
|
}
|
|
1420
|
-
const paramName = param
|
|
1421
|
-
? `context.${param.name}`
|
|
1422
|
-
: param.optional
|
|
1423
|
-
? `${optionalParamName}["${param.name}"]`
|
|
1424
|
-
: param.name;
|
|
1498
|
+
const paramName = getParamAccessor(param, optionalParamName);
|
|
1425
1499
|
return defaultValue
|
|
1426
1500
|
? typeof defaultValue === "string"
|
|
1427
1501
|
? `${paramName} ?? "${defaultValue}"`
|
|
@@ -2132,67 +2206,71 @@ export function getOperationResponseTypeName(method) {
|
|
|
2132
2206
|
: "";
|
|
2133
2207
|
return `${prefix}${normalizeName(operation.name, NameType.Interface)}Response`;
|
|
2134
2208
|
}
|
|
2209
|
+
/**
|
|
2210
|
+
* Returns true when a type should be wrapped with a `body` property.
|
|
2211
|
+
* Wrapping is needed for primitive/enum types; composite (model, dict, model-array)
|
|
2212
|
+
* and unknown-as-record types map to the HLC PropertyKind.Composite / Dictionary
|
|
2213
|
+
* patterns which do NOT get a body wrapper.
|
|
2214
|
+
*
|
|
2215
|
+
* Covered cases (no wrap):
|
|
2216
|
+
* - model array (e.g. Foo[]) → HLC PropertyKind.Composite
|
|
2217
|
+
* - model → HLC PropertyKind.Composite
|
|
2218
|
+
* - dict / Record<string, unknown> → HLC PropertyKind.Dictionary
|
|
2219
|
+
* - unknown with treatUnknownAsRecord → treated as Dict
|
|
2220
|
+
*
|
|
2221
|
+
* Covered cases (wrap):
|
|
2222
|
+
* - string, boolean, number → HLC PropertyKind.Primitive
|
|
2223
|
+
* - string[] → HLC PropertyKind.Primitive (item kind)
|
|
2224
|
+
* - enum / KnownXxx | string → HLC PropertyKind.Enum
|
|
2225
|
+
* - any / unknown (no treatAsRecord) → HLC PropertyKind.Primitive
|
|
2226
|
+
*/
|
|
2227
|
+
function isWrappableType(context, type) {
|
|
2228
|
+
var _a;
|
|
2229
|
+
if (type.kind === "array" && type.valueType.kind === "model")
|
|
2230
|
+
return false;
|
|
2231
|
+
if (type.kind === "dict" || type.kind === "model")
|
|
2232
|
+
return false;
|
|
2233
|
+
if (type.kind === "unknown" && ((_a = context.rlcOptions) === null || _a === void 0 ? void 0 : _a.treatUnknownAsRecord))
|
|
2234
|
+
return false;
|
|
2235
|
+
return true;
|
|
2236
|
+
}
|
|
2135
2237
|
/**
|
|
2136
2238
|
* Determines whether wrapping the non-model return type is needed for an operation.
|
|
2137
2239
|
* Returns an object with `shouldWrap` (whether to wrap) and `isBinary` (whether it's a binary response).
|
|
2138
2240
|
*/
|
|
2139
2241
|
export function checkWrapNonModelReturn(context, operation) {
|
|
2140
|
-
var _a, _b, _c, _d;
|
|
2242
|
+
var _a, _b, _c, _d, _e;
|
|
2141
2243
|
const noWrap = { shouldWrap: false, isBinary: false };
|
|
2142
|
-
//
|
|
2143
|
-
if (
|
|
2144
|
-
isLroAndPagingOperation(operation) ||
|
|
2145
|
-
isPagingOnlyOperation(operation)) {
|
|
2244
|
+
// LRO+paging and paging-only operations are not wrapped
|
|
2245
|
+
if (isLroAndPagingOperation(operation) || isPagingOnlyOperation(operation)) {
|
|
2146
2246
|
return noWrap;
|
|
2147
2247
|
}
|
|
2148
2248
|
// Only if the feature flag is enabled
|
|
2149
2249
|
if (!((_a = context.rlcOptions) === null || _a === void 0 ? void 0 : _a.wrapNonModelReturn)) {
|
|
2150
2250
|
return noWrap;
|
|
2151
2251
|
}
|
|
2152
|
-
|
|
2153
|
-
if (
|
|
2252
|
+
// For LRO-only operations, check the final result type from LRO metadata
|
|
2253
|
+
if (isLroOnlyOperation(operation)) {
|
|
2254
|
+
const lroResultType = (_c = (_b = operation.lroMetadata) === null || _b === void 0 ? void 0 : _b.finalResponse) === null || _c === void 0 ? void 0 : _c.result;
|
|
2255
|
+
if (!lroResultType) {
|
|
2256
|
+
return noWrap; // void LRO - no wrap needed
|
|
2257
|
+
}
|
|
2258
|
+
return {
|
|
2259
|
+
shouldWrap: isWrappableType(context, lroResultType),
|
|
2260
|
+
isBinary: false
|
|
2261
|
+
};
|
|
2262
|
+
}
|
|
2263
|
+
const { type } = operation.response;
|
|
2264
|
+
if (!type) {
|
|
2154
2265
|
return noWrap; // void return type - no wrap needed
|
|
2155
2266
|
}
|
|
2156
|
-
const
|
|
2157
|
-
|
|
2158
|
-
// Determine whether to wrap based on the HLC PropertyKind mapping.
|
|
2159
|
-
// HLC wraps with `body` only when the type is PropertyKind.Primitive or PropertyKind.Enum
|
|
2160
|
-
// (i.e. NOT PropertyKind.Composite or PropertyKind.Dictionary).
|
|
2161
|
-
// For array types, HLC uses the item's kind, not the array itself.
|
|
2162
|
-
//
|
|
2163
|
-
// Case: bytes with binary content type → binary wrap (isBinary=true)
|
|
2267
|
+
const contentTypes = (_e = (_d = operation.operation.responses[0]) === null || _d === void 0 ? void 0 : _d.contentTypes) !== null && _e !== void 0 ? _e : [];
|
|
2268
|
+
// bytes with binary content type → binary wrap (isBinary=true)
|
|
2164
2269
|
// HLC: bytes → binary payload → separate binary handling
|
|
2165
2270
|
if (type.__raw && isBinaryPayload(context, type.__raw, contentTypes)) {
|
|
2166
2271
|
return { shouldWrap: true, isBinary: true };
|
|
2167
2272
|
}
|
|
2168
|
-
|
|
2169
|
-
// HLC: model array → PropertyKind.Composite (item kind = model) → no body wrapper
|
|
2170
|
-
// Modular: array with valueType.kind === "model"
|
|
2171
|
-
if (type.kind === "array" && type.valueType.kind === "model") {
|
|
2172
|
-
return noWrap;
|
|
2173
|
-
}
|
|
2174
|
-
// Case: any object / Record (e.g. Record<string, unknown>) → no wrap
|
|
2175
|
-
// HLC: SchemaType.AnyObject → PropertyKind.Dictionary → no body wrapper
|
|
2176
|
-
// Modular: kind === "dict"
|
|
2177
|
-
// Case: model → no wrap
|
|
2178
|
-
// HLC: model → PropertyKind.Composite → no body wrapper
|
|
2179
|
-
// Modular: kind === "model"
|
|
2180
|
-
if (type.kind === "dict" || type.kind === "model") {
|
|
2181
|
-
return noWrap;
|
|
2182
|
-
}
|
|
2183
|
-
// Case: unknown with treatUnknownAsRecord enabled → no wrap
|
|
2184
|
-
// When treatUnknownAsRecord is enabled, `unknown` is treated as Record<string, unknown>
|
|
2185
|
-
// which maps to HLC PropertyKind.Dictionary → no body wrapper
|
|
2186
|
-
if (type.kind === "unknown" && ((_d = context.rlcOptions) === null || _d === void 0 ? void 0 : _d.treatUnknownAsRecord)) {
|
|
2187
|
-
return noWrap;
|
|
2188
|
-
}
|
|
2189
|
-
// Remaining cases → wrap with `body`:
|
|
2190
|
-
// - string → HLC PropertyKind.Primitive → modular `string`
|
|
2191
|
-
// - boolean → HLC PropertyKind.Primitive → modular `boolean`
|
|
2192
|
-
// - string[] → HLC PropertyKind.Primitive (array keeps item kind) → modular `string[]`
|
|
2193
|
-
// - any → HLC PropertyKind.Primitive → modular `unknown` or `any`
|
|
2194
|
-
// - enum → HLC PropertyKind.Enum → modular `KnownXxx | string`
|
|
2195
|
-
return { shouldWrap: true, isBinary: false };
|
|
2273
|
+
return { shouldWrap: isWrappableType(context, type), isBinary: false };
|
|
2196
2274
|
}
|
|
2197
2275
|
/**
|
|
2198
2276
|
* Builds a TypeAliasDeclarationStructure for the non-model response wrapper type.
|