@azure-tools/typespec-ts 0.46.1 → 0.47.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.
Files changed (84) hide show
  1. package/CHANGELOG.md +15 -3
  2. package/LICENSE +21 -0
  3. package/dist/src/framework/hooks/sdkTypes.d.ts +7 -1
  4. package/dist/src/framework/hooks/sdkTypes.d.ts.map +1 -1
  5. package/dist/src/framework/hooks/sdkTypes.js +59 -1
  6. package/dist/src/framework/hooks/sdkTypes.js.map +1 -1
  7. package/dist/src/index.d.ts.map +1 -1
  8. package/dist/src/index.js +2 -1
  9. package/dist/src/index.js.map +1 -1
  10. package/dist/src/lib.d.ts +20 -1
  11. package/dist/src/lib.d.ts.map +1 -1
  12. package/dist/src/lib.js +18 -1
  13. package/dist/src/lib.js.map +1 -1
  14. package/dist/src/modular/buildClassicalClient.d.ts.map +1 -1
  15. package/dist/src/modular/buildClassicalClient.js +137 -23
  16. package/dist/src/modular/buildClassicalClient.js.map +1 -1
  17. package/dist/src/modular/buildRootIndex.d.ts +2 -1
  18. package/dist/src/modular/buildRootIndex.d.ts.map +1 -1
  19. package/dist/src/modular/buildRootIndex.js +23 -0
  20. package/dist/src/modular/buildRootIndex.js.map +1 -1
  21. package/dist/src/modular/emitModels.d.ts.map +1 -1
  22. package/dist/src/modular/emitModels.js +57 -14
  23. package/dist/src/modular/emitModels.js.map +1 -1
  24. package/dist/src/modular/emitSamples.d.ts.map +1 -1
  25. package/dist/src/modular/emitSamples.js +53 -26
  26. package/dist/src/modular/emitSamples.js.map +1 -1
  27. package/dist/src/modular/helpers/classicalOperationHelpers.d.ts.map +1 -1
  28. package/dist/src/modular/helpers/classicalOperationHelpers.js +73 -23
  29. package/dist/src/modular/helpers/classicalOperationHelpers.js.map +1 -1
  30. package/dist/src/modular/helpers/operationHelpers.d.ts +7 -4
  31. package/dist/src/modular/helpers/operationHelpers.d.ts.map +1 -1
  32. package/dist/src/modular/helpers/operationHelpers.js +115 -23
  33. package/dist/src/modular/helpers/operationHelpers.js.map +1 -1
  34. package/dist/src/modular/helpers/typeHelpers.d.ts +3 -1
  35. package/dist/src/modular/helpers/typeHelpers.d.ts.map +1 -1
  36. package/dist/src/modular/helpers/typeHelpers.js +7 -3
  37. package/dist/src/modular/helpers/typeHelpers.js.map +1 -1
  38. package/dist/src/modular/serialization/buildDeserializerFunction.d.ts +4 -2
  39. package/dist/src/modular/serialization/buildDeserializerFunction.d.ts.map +1 -1
  40. package/dist/src/modular/serialization/buildDeserializerFunction.js +60 -17
  41. package/dist/src/modular/serialization/buildDeserializerFunction.js.map +1 -1
  42. package/dist/src/modular/serialization/buildSerializerFunction.d.ts +4 -2
  43. package/dist/src/modular/serialization/buildSerializerFunction.d.ts.map +1 -1
  44. package/dist/src/modular/serialization/buildSerializerFunction.js +61 -19
  45. package/dist/src/modular/serialization/buildSerializerFunction.js.map +1 -1
  46. package/dist/src/modular/serialization/serializeUtils.d.ts +11 -0
  47. package/dist/src/modular/serialization/serializeUtils.d.ts.map +1 -1
  48. package/dist/src/modular/serialization/serializeUtils.js +15 -0
  49. package/dist/src/modular/serialization/serializeUtils.js.map +1 -1
  50. package/dist/src/modular/static-helpers-metadata.d.ts +17 -0
  51. package/dist/src/modular/static-helpers-metadata.d.ts.map +1 -1
  52. package/dist/src/modular/static-helpers-metadata.js +17 -0
  53. package/dist/src/modular/static-helpers-metadata.js.map +1 -1
  54. package/dist/src/transform/transfromRLCOptions.d.ts.map +1 -1
  55. package/dist/src/transform/transfromRLCOptions.js +2 -0
  56. package/dist/src/transform/transfromRLCOptions.js.map +1 -1
  57. package/dist/src/utils/namespaceUtils.d.ts.map +1 -1
  58. package/dist/src/utils/namespaceUtils.js +19 -4
  59. package/dist/src/utils/namespaceUtils.js.map +1 -1
  60. package/dist/src/utils/operationUtil.d.ts +1 -0
  61. package/dist/src/utils/operationUtil.d.ts.map +1 -1
  62. package/dist/src/utils/operationUtil.js +26 -0
  63. package/dist/src/utils/operationUtil.js.map +1 -1
  64. package/dist/tsconfig.tsbuildinfo +1 -1
  65. package/package.json +7 -11
  66. package/src/framework/hooks/sdkTypes.ts +102 -2
  67. package/src/index.ts +2 -0
  68. package/src/lib.ts +20 -1
  69. package/src/modular/buildClassicalClient.ts +182 -25
  70. package/src/modular/buildRootIndex.ts +53 -1
  71. package/src/modular/emitModels.ts +72 -19
  72. package/src/modular/emitSamples.ts +86 -21
  73. package/src/modular/helpers/classicalOperationHelpers.ts +112 -30
  74. package/src/modular/helpers/operationHelpers.ts +163 -43
  75. package/src/modular/helpers/typeHelpers.ts +19 -3
  76. package/src/modular/serialization/buildDeserializerFunction.ts +87 -35
  77. package/src/modular/serialization/buildSerializerFunction.ts +86 -36
  78. package/src/modular/serialization/serializeUtils.ts +37 -0
  79. package/src/modular/static-helpers-metadata.ts +18 -0
  80. package/src/transform/transfromRLCOptions.ts +2 -0
  81. package/src/utils/namespaceUtils.ts +19 -3
  82. package/src/utils/operationUtil.ts +35 -0
  83. package/static/static-helpers/serialization/check-prop-undefined.ts +17 -0
  84. package/static/static-helpers/simplePollerHelpers.ts +125 -0
@@ -24,8 +24,10 @@ import {
24
24
  ServiceOperation
25
25
  } from "../../utils/operationUtil.js";
26
26
  import {
27
+ getPropertyWithOverrides,
27
28
  isNormalUnion,
28
- isSpecialHandledUnion
29
+ isSpecialHandledUnion,
30
+ ModelOverrideOptions
29
31
  } from "../serialization/serializeUtils.js";
30
32
  import {
31
33
  getDocsFromDescription,
@@ -33,8 +35,14 @@ import {
33
35
  } from "./docsHelpers.js";
34
36
  import { AzurePollingDependencies } from "../external-dependencies.js";
35
37
  import { NameType, normalizeName } from "@azure-tools/rlc-common";
36
- import { buildModelDeserializer } from "../serialization/buildDeserializerFunction.js";
37
- import { buildModelSerializer } from "../serialization/buildSerializerFunction.js";
38
+ import {
39
+ buildModelDeserializer,
40
+ buildPropertyDeserializer
41
+ } from "../serialization/buildDeserializerFunction.js";
42
+ import {
43
+ buildModelSerializer,
44
+ buildPropertySerializer
45
+ } from "../serialization/buildSerializerFunction.js";
38
46
  import { refkey } from "../../framework/refkey.js";
39
47
  import { reportDiagnostic } from "../../lib.js";
40
48
  import { resolveReference } from "../../framework/reference.js";
@@ -64,6 +72,7 @@ import {
64
72
  SdkType
65
73
  } from "@azure-tools/typespec-client-generator-core";
66
74
  import { isMetadata } from "@typespec/http";
75
+ import { useContext } from "../../contextManager.js";
67
76
 
68
77
  export function getSendPrivateFunction(
69
78
  dpgContext: SdkContext,
@@ -221,8 +230,10 @@ export function getDeserializePrivateFunction(
221
230
  const deserializeFunctionName = buildModelDeserializer(
222
231
  context,
223
232
  deserializedType,
224
- false,
225
- true
233
+ {
234
+ nameOnly: true,
235
+ skipDiscriminatedUnionSuffix: false
236
+ }
226
237
  );
227
238
  if (deserializeFunctionName) {
228
239
  statements.push(`return ${deserializeFunctionName}(${deserializedRoot})`);
@@ -277,8 +288,10 @@ function getExceptionDetails(
277
288
  const deserializeFunctionName = buildModelDeserializer(
278
289
  context,
279
290
  exception.type,
280
- false,
281
- true
291
+ {
292
+ nameOnly: true,
293
+ skipDiscriminatedUnionSuffix: false
294
+ }
282
295
  );
283
296
  if (
284
297
  !deserializeFunctionName ||
@@ -421,7 +434,11 @@ export function getOperationFunction(
421
434
  context: SdkContext,
422
435
  method: [string[], ServiceOperation],
423
436
  clientType: string
424
- ): FunctionDeclarationStructure & { propertyName?: string } {
437
+ ): FunctionDeclarationStructure & {
438
+ propertyName?: string;
439
+ isLro?: boolean;
440
+ lroFinalReturnType?: string;
441
+ } {
425
442
  const operation = method[1];
426
443
  // Extract required parameters
427
444
  const parameters: OptionalKind<ParameterDeclarationStructure>[] =
@@ -498,7 +515,11 @@ function getLroOnlyOperationFunction(
498
515
  method: [string[], SdkLroServiceMethod<SdkHttpOperation>],
499
516
  clientType: string,
500
517
  optionalParamName: string = "options"
501
- ): FunctionDeclarationStructure & { propertyName?: string } {
518
+ ): FunctionDeclarationStructure & {
519
+ propertyName?: string;
520
+ isLro?: boolean;
521
+ lroFinalReturnType?: string;
522
+ } {
502
523
  const operation = method[1];
503
524
  // Extract required parameters
504
525
  const parameters: OptionalKind<ParameterDeclarationStructure>[] =
@@ -521,6 +542,8 @@ function getLroOnlyOperationFunction(
521
542
  isExported: true,
522
543
  name,
523
544
  propertyName: normalizeName(operation.name, NameType.Property),
545
+ isLro: true,
546
+ lroFinalReturnType: returnType.type,
524
547
  parameters,
525
548
  returnType: `${pollerLikeReference}<${operationStateReference}<${returnType.type}>, ${returnType.type}>`
526
549
  };
@@ -799,8 +822,10 @@ function buildBodyParameter(
799
822
  const serializerFunctionName = buildModelSerializer(
800
823
  context,
801
824
  getNullableValidType(bodyParameter.type),
802
- false,
803
- true
825
+ {
826
+ nameOnly: true,
827
+ skipDiscriminatedUnionSuffix: false
828
+ }
804
829
  );
805
830
 
806
831
  const bodyParamName = normalizeName(
@@ -1143,11 +1168,48 @@ function getNullableCheck(name: string, type: SdkType) {
1143
1168
  return `${name} === null ? null :`;
1144
1169
  }
1145
1170
 
1146
- export function getSerializationExpression(
1171
+ function getSerializationExpressionForFlatten(
1147
1172
  context: SdkContext,
1148
1173
  property: SdkModelPropertyType,
1149
1174
  propertyPath: string
1150
1175
  ): string {
1176
+ const serializeFunctionName = buildPropertySerializer(context, property, {
1177
+ nameOnly: true,
1178
+ skipDiscriminatedUnionSuffix: false
1179
+ });
1180
+ if (!serializeFunctionName) {
1181
+ return property.optional ? `undefined` : `{}`;
1182
+ }
1183
+ const validProps = getAllProperties(
1184
+ context,
1185
+ property.type,
1186
+ getAllAncestors(property.type)
1187
+ ).filter(
1188
+ (p) =>
1189
+ p.kind === "property" &&
1190
+ !isReadOnly(p) &&
1191
+ !isMetadata(context.program, p.__raw!)
1192
+ );
1193
+ if (validProps.length === 0) {
1194
+ return `undefined`;
1195
+ }
1196
+ const optionalPrefix = property.optional
1197
+ ? `${resolveReference(SerializationHelpers.areAllPropsUndefined)}(${propertyPath}, [${validProps
1198
+ .map((p) => `"${p.name}"`)
1199
+ .join(", ")}]) ? undefined : `
1200
+ : "";
1201
+ return `${optionalPrefix}${serializeFunctionName}(${propertyPath})`;
1202
+ }
1203
+
1204
+ export function getSerializationExpression(
1205
+ context: SdkContext,
1206
+ property: SdkModelPropertyType,
1207
+ propertyPath: string,
1208
+ enableFlatten: boolean = true
1209
+ ): string {
1210
+ if (property.flatten && enableFlatten) {
1211
+ return getSerializationExpressionForFlatten(context, property, "item");
1212
+ }
1151
1213
  const dot = propertyPath.endsWith("?") ? "." : "";
1152
1214
  const propertyPathWithDot = `${propertyPath ? `${propertyPath}${dot}` : `${dot}`}`;
1153
1215
  const nullOrUndefinedPrefix = getPropertySerializationPrefix(
@@ -1164,8 +1226,10 @@ export function getSerializationExpression(
1164
1226
  const serializeFunctionName = buildModelSerializer(
1165
1227
  context,
1166
1228
  getNullableValidType(property.type),
1167
- false,
1168
- true
1229
+ {
1230
+ nameOnly: true,
1231
+ skipDiscriminatedUnionSuffix: false
1232
+ }
1169
1233
  );
1170
1234
  if (serializeFunctionName) {
1171
1235
  return `${nullOrUndefinedPrefix}${serializeFunctionName}(${propertyFullName})`;
@@ -1186,7 +1250,9 @@ export function getSerializationExpression(
1186
1250
  export function getRequestModelProperties(
1187
1251
  context: SdkContext,
1188
1252
  modelPropertyType: SdkModelType & { optional?: boolean },
1189
- propertyPath: string = "body"
1253
+ propertyPath: string = "body",
1254
+ overrides?: ModelOverrideOptions,
1255
+ enableFlatten: boolean = true
1190
1256
  ): Array<[string, string]> {
1191
1257
  const props: [string, string][] = [];
1192
1258
  const allParents = getAllAncestors(modelPropertyType);
@@ -1195,16 +1261,17 @@ export function getRequestModelProperties(
1195
1261
  if (properties.length <= 0) {
1196
1262
  return [];
1197
1263
  }
1198
- for (const property of properties) {
1199
- if (property.kind === "property" && isReadOnly(property)) {
1264
+ for (const prop of properties) {
1265
+ if (prop.kind === "property" && isReadOnly(prop)) {
1200
1266
  continue;
1201
1267
  }
1202
- if (isMetadata(context.program, property.__raw!)) {
1268
+ if (isMetadata(context.program, prop.__raw!)) {
1203
1269
  continue;
1204
1270
  }
1271
+ const property = getPropertyWithOverrides(prop, overrides);
1205
1272
  props.push([
1206
1273
  getPropertySerializedName(property)!,
1207
- getSerializationExpression(context, property, propertyPath)
1274
+ getSerializationExpression(context, property, propertyPath, enableFlatten)
1208
1275
  ]);
1209
1276
  }
1210
1277
 
@@ -1219,12 +1286,16 @@ export function getRequestModelProperties(
1219
1286
  export function getRequestModelMapping(
1220
1287
  context: SdkContext,
1221
1288
  modelPropertyType: SdkModelType & { optional?: boolean },
1222
- propertyPath: string = "body"
1289
+ propertyPath: string = "body",
1290
+ overrides?: ModelOverrideOptions,
1291
+ enableFlatten: boolean = true
1223
1292
  ): string[] {
1224
1293
  return getRequestModelProperties(
1225
1294
  context,
1226
1295
  modelPropertyType,
1227
- propertyPath
1296
+ propertyPath,
1297
+ overrides,
1298
+ enableFlatten
1228
1299
  ).map(([name, value]) => `"${name}": ${value}`);
1229
1300
  }
1230
1301
 
@@ -1245,16 +1316,19 @@ function getPropertySerializedName(
1245
1316
  export function getResponseMapping(
1246
1317
  context: SdkContext,
1247
1318
  type: SdkType,
1248
- propertyPath: string = "result.body"
1319
+ propertyPath: string = "result.body",
1320
+ overrides?: ModelOverrideOptions,
1321
+ enableFlatten: boolean = true
1249
1322
  ) {
1250
1323
  const allParents = type.kind === "model" ? getAllAncestors(type) : [];
1251
1324
  const properties =
1252
1325
  type.kind === "model" ? getAllProperties(context, type, allParents) : [];
1253
1326
  const props: string[] = [];
1254
- for (const property of properties) {
1255
- if (isMetadata(context.program, property.__raw!)) {
1327
+ for (const prop of properties) {
1328
+ if (isMetadata(context.program, prop.__raw!)) {
1256
1329
  continue;
1257
1330
  }
1331
+ const property = getPropertyWithOverrides(prop, overrides);
1258
1332
  const dot = propertyPath.endsWith("?") ? "." : "";
1259
1333
  const serializedName = getPropertySerializedName(property);
1260
1334
  const restValue = `${
@@ -1265,17 +1339,29 @@ export function getResponseMapping(
1265
1339
  property.optional || isTypeNullable(property.type)
1266
1340
  ? `!${restValue}? ${restValue}: `
1267
1341
  : "";
1268
- const deserializeFunctionName = buildModelDeserializer(
1269
- context,
1270
- getNullableValidType(property.type),
1271
- false,
1272
- true
1273
- );
1342
+ const flattenContext =
1343
+ useContext("sdkTypes").flattenProperties.get(property);
1344
+ const isSupportedFlatten = flattenContext && enableFlatten;
1345
+ const deserializeFunctionName = isSupportedFlatten
1346
+ ? buildPropertyDeserializer(context, property, {
1347
+ nameOnly: true,
1348
+ skipDiscriminatedUnionSuffix: false
1349
+ })
1350
+ : buildModelDeserializer(context, getNullableValidType(property.type), {
1351
+ nameOnly: true,
1352
+ skipDiscriminatedUnionSuffix: false
1353
+ });
1274
1354
  const propertyName = normalizeModelPropertyName(context, property);
1275
1355
  if (deserializeFunctionName) {
1276
- props.push(
1277
- `${propertyName}: ${nullOrUndefinedPrefix}${deserializeFunctionName}(${restValue})`
1278
- );
1356
+ if (isSupportedFlatten) {
1357
+ props.push(
1358
+ `...${nullOrUndefinedPrefix}${deserializeFunctionName}(${restValue})`
1359
+ );
1360
+ } else {
1361
+ props.push(
1362
+ `${propertyName}: ${nullOrUndefinedPrefix}${deserializeFunctionName}(${restValue})`
1363
+ );
1364
+ }
1279
1365
  } else if (isAzureCoreErrorType(context.program, property.type.__raw)) {
1280
1366
  props.push(`${propertyName}: ${nullOrUndefinedPrefix}${restValue}`);
1281
1367
  } else {
@@ -1333,8 +1419,10 @@ export function serializeRequestValue(
1333
1419
  const serializeFunctionName = buildModelSerializer(
1334
1420
  context,
1335
1421
  getNullableValidType(type.valueType),
1336
- false,
1337
- true
1422
+ {
1423
+ nameOnly: true,
1424
+ skipDiscriminatedUnionSuffix: false
1425
+ }
1338
1426
  );
1339
1427
  if (serializeFunctionName) {
1340
1428
  return `${prefix}.map((p: any) => { return ${elementNullOrUndefinedPrefix}${serializeFunctionName}(p)})`;
@@ -1441,8 +1529,10 @@ export function deserializeResponseValue(
1441
1529
  ? buildModelDeserializer(
1442
1530
  context,
1443
1531
  getNullableValidType(type.valueType),
1444
- false,
1445
- true
1532
+ {
1533
+ nameOnly: true,
1534
+ skipDiscriminatedUnionSuffix: false
1535
+ }
1446
1536
  )
1447
1537
  : undefined;
1448
1538
  if (deserializeFunctionName) {
@@ -1458,6 +1548,38 @@ export function deserializeResponseValue(
1458
1548
  return restValue;
1459
1549
  }
1460
1550
  }
1551
+ case "dict": {
1552
+ const prefix = nullOrUndefinedPrefix + restValue;
1553
+ let elementNullOrUndefinedPrefix = "";
1554
+ if (
1555
+ type.valueType &&
1556
+ (isTypeNullable(type.valueType) || getOptionalForType(type.valueType))
1557
+ ) {
1558
+ elementNullOrUndefinedPrefix = "!p ? p :";
1559
+ }
1560
+ const deserializeFunctionName = type.valueType
1561
+ ? buildModelDeserializer(
1562
+ context,
1563
+ getNullableValidType(type.valueType),
1564
+ {
1565
+ nameOnly: true,
1566
+ skipDiscriminatedUnionSuffix: false
1567
+ }
1568
+ )
1569
+ : undefined;
1570
+ if (deserializeFunctionName) {
1571
+ return `Object.fromEntries(Object.entries(${prefix}).map(([k, p]: [string, any]) => [k, ${elementNullOrUndefinedPrefix}${deserializeFunctionName}(p)]))`;
1572
+ } else if (
1573
+ type.valueType &&
1574
+ isAzureCoreErrorType(context.program, type.valueType.__raw)
1575
+ ) {
1576
+ return `Object.fromEntries(Object.entries(${prefix}).map(([k, p]: [string, any]) => [k, ${elementNullOrUndefinedPrefix}p]))`;
1577
+ } else if (type.valueType) {
1578
+ return `Object.fromEntries(Object.entries(${prefix}).map(([k, p]: [string, any]) => [k, ${elementNullOrUndefinedPrefix}${deserializeResponseValue(context, type.valueType, "p", getEncodeForType(type.valueType))}]))`;
1579
+ } else {
1580
+ return restValue;
1581
+ }
1582
+ }
1461
1583
  case "bytes":
1462
1584
  if (format !== "binary" && format !== "bytes") {
1463
1585
  return `typeof ${restValue} === 'string'
@@ -1470,12 +1592,10 @@ export function deserializeResponseValue(
1470
1592
  return `${restValue}`;
1471
1593
  } else if (isSpecialHandledUnion(type)) {
1472
1594
  const deserializeFunctionName = type
1473
- ? buildModelDeserializer(
1474
- context,
1475
- getNullableValidType(type),
1476
- false,
1477
- true
1478
- )
1595
+ ? buildModelDeserializer(context, getNullableValidType(type), {
1596
+ nameOnly: true,
1597
+ skipDiscriminatedUnionSuffix: false
1598
+ })
1479
1599
  : undefined;
1480
1600
  if (deserializeFunctionName) {
1481
1601
  return `${deserializeFunctionName}(${restValue})`;
@@ -7,6 +7,12 @@ import {
7
7
  SdkModelType,
8
8
  SdkType
9
9
  } from "@azure-tools/typespec-client-generator-core";
10
+ import {
11
+ getPropertyWithOverrides,
12
+ ModelOverrideOptions
13
+ } from "../serialization/serializeUtils.js";
14
+ import { getAllAncestors, getAllProperties } from "./operationHelpers.js";
15
+ import { SdkContext } from "../../utils/interfaces.js";
10
16
 
11
17
  export function getDirectSubtypes(type: SdkModelType) {
12
18
  if (!type.discriminatedSubtypes) {
@@ -93,15 +99,25 @@ export function isCredentialType(
93
99
  * Builds a property name mapper between the serializedName and the name of the property.
94
100
  * Return empty map if the type is not a model.
95
101
  */
96
- export function buildPropertyNameMapper(model: SdkType) {
102
+ export function buildPropertyNameMapper(
103
+ context: SdkContext,
104
+ model: SdkType,
105
+ overrides?: ModelOverrideOptions
106
+ ) {
97
107
  const mapper = new Map<string, string>();
98
108
  if (model.kind !== "model") {
99
109
  return mapper;
100
110
  }
101
- for (const prop of model.properties) {
102
- if (prop.kind !== "property") {
111
+ const allProperties = getAllProperties(
112
+ context,
113
+ model,
114
+ getAllAncestors(model)
115
+ );
116
+ for (const p of allProperties) {
117
+ if (p.kind !== "property") {
103
118
  continue;
104
119
  }
120
+ const prop = getPropertyWithOverrides(p, overrides);
105
121
  mapper.set(
106
122
  prop.serializationOptions.json?.name || prop.name,
107
123
  normalizeName(prop.name, NameType.Property)
@@ -2,6 +2,7 @@ import { FunctionDeclarationStructure, StructureKind } from "ts-morph";
2
2
  import {
3
3
  SdkArrayType,
4
4
  SdkDictionaryType,
5
+ SdkModelPropertyType,
5
6
  SdkModelType,
6
7
  SdkType,
7
8
  SdkUnionType,
@@ -34,17 +35,55 @@ import {
34
35
  } from "../helpers/typeHelpers.js";
35
36
  import { reportDiagnostic } from "../../lib.js";
36
37
  import { NoTarget } from "@typespec/compiler";
38
+ import { useContext } from "../../contextManager.js";
39
+
40
+ export function buildPropertyDeserializer(
41
+ context: SdkContext,
42
+ property: SdkModelPropertyType,
43
+ options: ModelSerializeOptions = {
44
+ nameOnly: false,
45
+ skipDiscriminatedUnionSuffix: false
46
+ }
47
+ ) {
48
+ const propertyContext =
49
+ useContext("sdkTypes").flattenProperties.get(property);
50
+ // only build de-serializer for flatten property
51
+ if (property.flatten !== true || !propertyContext) {
52
+ return undefined;
53
+ }
54
+
55
+ const predefinedName = `_${normalizeName(
56
+ `${propertyContext.baseModel.name}_${property.name}`,
57
+ NameType.Method,
58
+ true
59
+ )}Deserializer`;
60
+ return buildModelDeserializer(context, property.type, {
61
+ ...options,
62
+ flatten: {
63
+ baseModel: propertyContext.baseModel,
64
+ property
65
+ },
66
+ overrides: {
67
+ allOptional: property.optional,
68
+ propertyRenames: propertyContext.conflictMap
69
+ },
70
+ predefinedName
71
+ });
72
+ }
37
73
 
38
74
  export function buildModelDeserializer(
39
75
  context: SdkContext,
40
76
  type: SdkType,
41
- skipDiscriminatedUnion = false,
42
- nameOnly: boolean = false
77
+ options: ModelSerializeOptions = {
78
+ nameOnly: false,
79
+ skipDiscriminatedUnionSuffix: false
80
+ }
43
81
  ): FunctionDeclarationStructure | undefined | string {
44
82
  // const modelTcgcType = getTcgcType(type) as SdkModelType;
45
83
  if (!isSupportedSerializeType(type)) {
46
84
  return undefined;
47
85
  }
86
+ const { nameOnly, skipDiscriminatedUnionSuffix } = options;
48
87
  if (type.kind === "model" || type.kind === "union" || type.kind === "enum") {
49
88
  if (
50
89
  !type.usage ||
@@ -72,16 +111,13 @@ export function buildModelDeserializer(
72
111
  return buildPolymorphicDeserializer(context, type, nameOnly);
73
112
  }
74
113
 
75
- if (isDiscriminatedUnion(type) && !skipDiscriminatedUnion) {
114
+ if (isDiscriminatedUnion(type) && !skipDiscriminatedUnionSuffix) {
76
115
  return buildDiscriminatedUnionDeserializer(context, type, nameOnly);
77
116
  }
78
117
 
79
118
  switch (type.kind) {
80
119
  case "model":
81
- return buildModelTypeDeserializer(context, type, {
82
- nameOnly,
83
- skipDiscriminatedUnionSuffix: skipDiscriminatedUnion
84
- });
120
+ return buildModelTypeDeserializer(context, type, options);
85
121
  case "union": // for non-discriminated union, we just return whatever we get
86
122
  return buildUnionDeserializer(context, type, nameOnly);
87
123
  case "dict":
@@ -220,6 +256,7 @@ function buildDiscriminatedUnionDeserializer(
220
256
  if (nameOnly) {
221
257
  return resolveReference(refkey(type, "deserializer"));
222
258
  }
259
+ // Get the base deserializer name and ensure reference tracking
223
260
  const baseDeserializerName = `${normalizeModelName(
224
261
  context,
225
262
  type,
@@ -241,12 +278,17 @@ function buildDiscriminatedUnionDeserializer(
241
278
  type.discriminatorProperty
242
279
  );
243
280
  const union = subType.discriminatedSubtypes ? "Union" : "";
244
- const subTypeName = `${normalizeName(subType.name, NameType.Interface, true)}${union}`;
245
- const subtypeDeserializerName = normalizeName(
246
- `${subTypeName}Deserializer`,
247
- NameType.Operation,
248
- true
281
+ const subTypeName = normalizeModelName(
282
+ context,
283
+ subType,
284
+ NameType.Interface,
285
+ !union
249
286
  );
287
+ // Get the deserializer name and ensure reference tracking
288
+ const subtypeDeserializerName = buildModelDeserializer(context, subType, {
289
+ nameOnly: true,
290
+ skipDiscriminatedUnionSuffix: false
291
+ }) as string;
250
292
 
251
293
  const caseLabels = discriminatedValues.map((value) => `case "${value}":`);
252
294
  cases.push(`
@@ -338,14 +380,18 @@ function buildModelTypeDeserializer(
338
380
  });
339
381
  return ""; // Return empty string to continue processing
340
382
  }
341
- const deserializerFunctionName = `${normalizeModelName(
342
- context,
343
- type,
344
- NameType.Operation,
345
- options.skipDiscriminatedUnionSuffix
346
- )}Deserializer`;
383
+ const deserializerFunctionName =
384
+ options.predefinedName ??
385
+ `${normalizeModelName(
386
+ context,
387
+ type,
388
+ NameType.Operation,
389
+ options.skipDiscriminatedUnionSuffix
390
+ )}Deserializer`;
347
391
  if (options.nameOnly) {
348
- return resolveReference(refkey(type, "deserializer"));
392
+ return options.flatten
393
+ ? resolveReference(refkey(options.flatten.property, "deserializer"))
394
+ : resolveReference(refkey(type, "deserializer"));
349
395
  }
350
396
  const deserializerFunction: FunctionDeclarationStructure = {
351
397
  kind: StructureKind.Function,
@@ -357,7 +403,9 @@ function buildModelTypeDeserializer(
357
403
  type: "any"
358
404
  }
359
405
  ],
360
- returnType: resolveReference(refkey(type)),
406
+ returnType: options.flatten
407
+ ? undefined // not set return type for flattened property deserializer and type system will infer correct one
408
+ : resolveReference(refkey(type)),
361
409
  statements: ["return item;"]
362
410
  };
363
411
  const nullabilityPrefix = "";
@@ -365,7 +413,13 @@ function buildModelTypeDeserializer(
365
413
  const additionalPropertiesSpread =
366
414
  getAdditionalPropertiesStatement(context, type) ?? "";
367
415
 
368
- const propertiesStr = getResponseMapping(context, type, "item");
416
+ const propertiesStr = getResponseMapping(
417
+ context,
418
+ type,
419
+ "item",
420
+ options.overrides,
421
+ !options.flatten
422
+ );
369
423
  const propertiesDeserialization = propertiesStr.filter((p) => p.trim());
370
424
 
371
425
  const output = [];
@@ -406,8 +460,10 @@ function getAdditionalPropertiesStatement(
406
460
  const deserializerFunction = buildModelDeserializer(
407
461
  context,
408
462
  additionalPropertyType,
409
- false,
410
- true
463
+ {
464
+ nameOnly: true,
465
+ skipDiscriminatedUnionSuffix: false
466
+ }
411
467
  );
412
468
  if (typeof deserializerFunction === "string") {
413
469
  params.push(deserializerFunction);
@@ -431,12 +487,10 @@ function buildDictTypeDeserializer(
431
487
  type: SdkDictionaryType,
432
488
  nameOnly = false
433
489
  ): FunctionDeclarationStructure | undefined | string {
434
- const valueDeserializer = buildModelDeserializer(
435
- context,
436
- type.valueType,
437
- false,
438
- true
439
- );
490
+ const valueDeserializer = buildModelDeserializer(context, type.valueType, {
491
+ nameOnly: true,
492
+ skipDiscriminatedUnionSuffix: false
493
+ });
440
494
  if (!valueDeserializer) {
441
495
  return undefined;
442
496
  }
@@ -490,12 +544,10 @@ function buildArrayTypeDeserializer(
490
544
  type: SdkArrayType,
491
545
  nameOnly = false
492
546
  ): FunctionDeclarationStructure | undefined | string {
493
- const valueDeserializer = buildModelDeserializer(
494
- context,
495
- type.valueType,
496
- false,
497
- true
498
- );
547
+ const valueDeserializer = buildModelDeserializer(context, type.valueType, {
548
+ nameOnly: true,
549
+ skipDiscriminatedUnionSuffix: false
550
+ });
499
551
  if (!valueDeserializer) {
500
552
  return undefined;
501
553
  }