@azure-tools/typespec-ts 0.28.0 → 0.29.0-alpha.20240531.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/src/index.d.ts +2 -0
  3. package/dist/src/index.d.ts.map +1 -1
  4. package/dist/src/index.js +24 -18
  5. package/dist/src/index.js.map +1 -1
  6. package/dist/src/lib.d.ts +14 -4
  7. package/dist/src/lib.d.ts.map +1 -1
  8. package/dist/src/lib.js +9 -2
  9. package/dist/src/lib.js.map +1 -1
  10. package/dist/src/modular/buildClassicalClient.d.ts.map +1 -1
  11. package/dist/src/modular/buildClassicalClient.js +2 -0
  12. package/dist/src/modular/buildClassicalClient.js.map +1 -1
  13. package/dist/src/modular/buildClassicalOperationGroups.d.ts.map +1 -1
  14. package/dist/src/modular/buildClassicalOperationGroups.js +3 -0
  15. package/dist/src/modular/buildClassicalOperationGroups.js.map +1 -1
  16. package/dist/src/modular/buildCodeModel.d.ts.map +1 -1
  17. package/dist/src/modular/buildCodeModel.js +80 -83
  18. package/dist/src/modular/buildCodeModel.js.map +1 -1
  19. package/dist/src/modular/buildLroFiles.d.ts +24 -0
  20. package/dist/src/modular/buildLroFiles.d.ts.map +1 -0
  21. package/dist/src/modular/buildLroFiles.js +399 -0
  22. package/dist/src/modular/buildLroFiles.js.map +1 -0
  23. package/dist/src/modular/buildOperations.d.ts +6 -0
  24. package/dist/src/modular/buildOperations.d.ts.map +1 -1
  25. package/dist/src/modular/buildOperations.js +64 -5
  26. package/dist/src/modular/buildOperations.js.map +1 -1
  27. package/dist/src/modular/buildPagingFiles.js +3 -3
  28. package/dist/src/modular/buildPagingFiles.js.map +1 -1
  29. package/dist/src/modular/buildProjectFiles.d.ts +0 -3
  30. package/dist/src/modular/buildProjectFiles.d.ts.map +1 -1
  31. package/dist/src/modular/buildProjectFiles.js +0 -399
  32. package/dist/src/modular/buildProjectFiles.js.map +1 -1
  33. package/dist/src/modular/buildRootIndex.d.ts.map +1 -1
  34. package/dist/src/modular/buildRootIndex.js +20 -0
  35. package/dist/src/modular/buildRootIndex.js.map +1 -1
  36. package/dist/src/modular/buildSubpathIndex.js +4 -3
  37. package/dist/src/modular/buildSubpathIndex.js.map +1 -1
  38. package/dist/src/modular/emitModels.d.ts +2 -0
  39. package/dist/src/modular/emitModels.d.ts.map +1 -1
  40. package/dist/src/modular/emitModels.js +73 -11
  41. package/dist/src/modular/emitModels.js.map +1 -1
  42. package/dist/src/modular/helpers/operationHelpers.d.ts +5 -5
  43. package/dist/src/modular/helpers/operationHelpers.d.ts.map +1 -1
  44. package/dist/src/modular/helpers/operationHelpers.js +171 -55
  45. package/dist/src/modular/helpers/operationHelpers.js.map +1 -1
  46. package/dist/src/modular/helpers/typeHelpers.d.ts.map +1 -1
  47. package/dist/src/modular/helpers/typeHelpers.js +6 -1
  48. package/dist/src/modular/helpers/typeHelpers.js.map +1 -1
  49. package/dist/src/modular/interfaces.d.ts +5 -0
  50. package/dist/src/modular/interfaces.d.ts.map +1 -1
  51. package/dist/src/modular/modularCodeModel.d.ts +9 -1
  52. package/dist/src/modular/modularCodeModel.d.ts.map +1 -1
  53. package/dist/src/transform/transformHelperFunctionDetails.js +1 -1
  54. package/dist/src/transform/transformParameters.js +2 -2
  55. package/dist/src/transform/transformParameters.js.map +1 -1
  56. package/dist/src/transform/transformPaths.js +1 -1
  57. package/dist/src/transform/transformPaths.js.map +1 -1
  58. package/dist/src/transform/transformResponses.js +2 -2
  59. package/dist/src/transform/transformResponses.js.map +1 -1
  60. package/dist/src/transform/transformSchemas.d.ts.map +1 -1
  61. package/dist/src/transform/transformSchemas.js +23 -31
  62. package/dist/src/transform/transformSchemas.js.map +1 -1
  63. package/dist/src/transform/transfromRLCOptions.d.ts.map +1 -1
  64. package/dist/src/transform/transfromRLCOptions.js +8 -1
  65. package/dist/src/transform/transfromRLCOptions.js.map +1 -1
  66. package/dist/src/utils/modelUtils.d.ts +12 -2
  67. package/dist/src/utils/modelUtils.d.ts.map +1 -1
  68. package/dist/src/utils/modelUtils.js +88 -49
  69. package/dist/src/utils/modelUtils.js.map +1 -1
  70. package/dist/tsconfig.tsbuildinfo +1 -1
  71. package/package.json +19 -18
  72. package/src/index.ts +36 -22
  73. package/src/lib.ts +10 -2
  74. package/src/modular/buildClassicalClient.ts +2 -0
  75. package/src/modular/buildClassicalOperationGroups.ts +4 -0
  76. package/src/modular/buildCodeModel.ts +100 -155
  77. package/src/modular/buildLroFiles.ts +433 -0
  78. package/src/modular/buildOperations.ts +91 -10
  79. package/src/modular/buildPagingFiles.ts +4 -4
  80. package/src/modular/buildProjectFiles.ts +0 -471
  81. package/src/modular/buildRootIndex.ts +49 -0
  82. package/src/modular/buildSubpathIndex.ts +4 -4
  83. package/src/modular/emitModels.ts +102 -15
  84. package/src/modular/helpers/operationHelpers.ts +207 -72
  85. package/src/modular/helpers/typeHelpers.ts +6 -2
  86. package/src/modular/interfaces.ts +6 -0
  87. package/src/modular/modularCodeModel.ts +10 -1
  88. package/src/transform/transformHelperFunctionDetails.ts +1 -1
  89. package/src/transform/transformParameters.ts +2 -2
  90. package/src/transform/transformPaths.ts +1 -1
  91. package/src/transform/transformResponses.ts +2 -2
  92. package/src/transform/transformSchemas.ts +22 -33
  93. package/src/transform/transfromRLCOptions.ts +10 -1
  94. package/src/utils/modelUtils.ts +107 -46
@@ -19,24 +19,48 @@ function isAzureCoreErrorSdkType(t: Type) {
19
19
  ["error", "errormodel", "innererror", "errorresponse"].includes(
20
20
  t.name.toLowerCase()
21
21
  ) &&
22
- t.isCoreErrorType === true
22
+ t.coreTypeInfo === "ErrorType"
23
23
  );
24
24
  }
25
25
 
26
+ function isAzureCoreLroSdkType(t: Type) {
27
+ return (
28
+ t.name &&
29
+ ["operationstate"].includes(t.name.toLowerCase()) &&
30
+ t.coreTypeInfo === "LroType"
31
+ );
32
+ }
33
+
34
+ function isAnonymousModel(t: Type) {
35
+ return t.type === "model" && t.name === "";
36
+ }
37
+
38
+ export function isModelWithAdditionalProperties(t: Type) {
39
+ return t.type === "dict" && t.name !== "Record";
40
+ }
41
+
26
42
  function getCoreClientErrorType(name: string, coreClientTypes: Set<string>) {
27
43
  const coreClientType: string = name === "Error" ? "ErrorModel" : name;
28
44
  coreClientTypes.add(coreClientType);
29
45
  return coreClientType;
30
46
  }
31
47
 
48
+ function getCoreLroType(name: string, coreLroTypes: Set<string>) {
49
+ const coreLroType = name === "OperationState" ? "CoreOperationStatus" : name;
50
+ coreLroTypes.add(coreLroType);
51
+ return coreLroType;
52
+ }
53
+
32
54
  // ====== TYPE EXTRACTION ======
33
55
 
34
56
  function extractModels(codeModel: ModularCodeModel): Type[] {
35
57
  const models = codeModel.types.filter(
36
58
  (t) =>
37
- (t.type === "model" || t.type === "enum") &&
38
- !isAzureCoreErrorSdkType(t) &&
39
- !(t.type == "model" && t.name === "")
59
+ ((t.type === "model" || t.type === "enum") &&
60
+ !isAzureCoreErrorSdkType(t) &&
61
+ !isAzureCoreLroSdkType(t) &&
62
+ !isAnonymousModel(t)) ||
63
+ isModelWithAdditionalProperties(t)
40
64
  );
41
65
 
42
66
  for (const model of codeModel.types) {
@@ -59,7 +83,10 @@ function extractModels(codeModel: ModularCodeModel): Type[] {
59
83
  export function extractAliases(codeModel: ModularCodeModel): Type[] {
60
84
  const models = codeModel.types.filter(
61
85
  (t) =>
62
- (t.type === "model" || t.type === "combined") && t.alias && t.aliasType
86
+ ((t.type === "model" || t.type === "combined") &&
87
+ t.alias &&
88
+ t.aliasType) ||
89
+ (isModelWithAdditionalProperties(t) && t.alias && t.aliasType)
63
90
  );
64
91
  return models;
65
92
  }
@@ -102,7 +129,7 @@ type InterfaceStructure = OptionalKind<InterfaceDeclarationStructure> & {
102
129
 
103
130
  export function buildModelInterface(
104
131
  model: Type,
105
- cache: { coreClientTypes: Set<string> }
132
+ cache: { coreClientTypes: Set<string>; coreLroTypes: Set<string> }
106
133
  ): InterfaceStructure {
107
134
  const modelProperties = model.properties ?? [];
108
135
  const modelInterface = {
@@ -114,9 +141,13 @@ export function buildModelInterface(
114
141
  const propertyMetadata = getType(p.type, p.format);
115
142
  let propertyTypeName = propertyMetadata.name;
116
143
  if (isAzureCoreErrorSdkType(p.type)) {
117
- propertyTypeName = isAzureCoreErrorSdkType(p.type)
118
- ? getCoreClientErrorType(propertyTypeName, cache.coreClientTypes)
119
- : propertyTypeName;
144
+ propertyTypeName = getCoreClientErrorType(
145
+ propertyTypeName,
146
+ cache.coreClientTypes
147
+ );
148
+ }
149
+ if (isAzureCoreLroSdkType(p.type)) {
150
+ propertyTypeName = getCoreLroType(propertyTypeName, cache.coreLroTypes);
120
151
  }
121
152
 
122
153
  return {
@@ -142,6 +173,7 @@ export function buildModels(
142
173
  ): SourceFile | undefined {
143
174
  // We are generating both models and enums here
144
175
  const coreClientTypes = new Set<string>();
176
+ const coreLroTypes = new Set<string>();
145
177
  // filter out the models/enums that are anonymous
146
178
  const models = extractModels(codeModel).filter((m) => !!m.name);
147
179
  const aliases = extractAliases(codeModel);
@@ -163,12 +195,21 @@ export function buildModels(
163
195
  const enumAlias = buildEnumModel(model);
164
196
  modelsFile.addTypeAlias(enumAlias);
165
197
  } else {
166
- const modelInterface = buildModelInterface(model, { coreClientTypes });
167
- model.type === "model"
168
- ? model.parents?.forEach((p) =>
169
- modelInterface.extends.push(p.alias ?? getType(p, p.format).name)
170
- )
171
- : undefined;
198
+ const modelInterface = buildModelInterface(model, {
199
+ coreClientTypes,
200
+ coreLroTypes
201
+ });
202
+
203
+ model.parents?.forEach((p) =>
204
+ modelInterface.extends.push(p.alias ?? getType(p, p.format).name)
205
+ );
206
+ if (isModelWithAdditionalProperties(model)) {
207
+ addExtendedDictInfo(
208
+ model,
209
+ modelInterface,
210
+ codeModel.modularOptions.compatibilityMode
211
+ );
212
+ }
172
213
  modelsFile.addInterface(modelInterface);
173
214
  }
174
215
  }
@@ -185,12 +226,58 @@ export function buildModels(
185
226
  ]);
186
227
  }
187
228
 
229
+ if (coreLroTypes.size > 0) {
230
+ modelsFile.addImportDeclarations([
231
+ {
232
+ moduleSpecifier: getImportSpecifier(
233
+ "azureCoreLro",
234
+ codeModel.runtimeImports
235
+ ),
236
+ namedImports: Array.from(coreLroTypes).map((t) =>
237
+ t === "CoreOperationStatus"
238
+ ? "OperationStatus as CoreOperationStatus"
239
+ : t
240
+ )
241
+ }
242
+ ]);
243
+ }
244
+
188
245
  aliases.forEach((alias) => {
189
246
  modelsFile.addTypeAlias(buildModelTypeAlias(alias));
190
247
  });
191
248
  return modelsFile;
192
249
  }
193
250
 
251
+ function addExtendedDictInfo(
252
+ model: Type,
253
+ modelInterface: InterfaceStructure,
254
+ compatibilityMode: boolean = false
255
+ ) {
256
+ if (
257
+ (model.properties &&
258
+ model.properties.length > 0 &&
259
+ model.elementType &&
260
+ model.properties?.every((p) => {
261
+ return getType(model.elementType!)?.name.includes(getType(p.type).name);
262
+ })) ||
263
+ (model.properties?.length === 0 && model.elementType)
264
+ ) {
265
+ modelInterface.extends.push(
266
+ `Record<string, ${getType(model.elementType!).name ?? "any"}>`
267
+ );
268
+ } else if (compatibilityMode) {
269
+ modelInterface.extends.push(`Record<string, any>`);
270
+ } else {
271
+ modelInterface.properties?.push({
272
+ name: "additionalProperties",
273
+ docs: ["Additional properties"],
274
+ hasQuestionToken: true,
275
+ isReadonly: false,
276
+ type: `Record<string, ${getType(model.elementType!).name ?? "any"}>`
277
+ });
278
+ }
279
+ }
280
+
194
281
  export function buildModelTypeAlias(model: Type) {
195
282
  return {
196
283
  name: model.name!,
@@ -59,6 +59,15 @@ function getRLCResponseType(rlcResponse?: OperationResponse) {
59
59
  .join(" | ");
60
60
  }
61
61
 
62
+ function getRLCLroLogicalResponse(rlcResponse?: OperationResponse) {
63
+ const logicalResponse = (rlcResponse?.responses ?? []).filter(
64
+ (r) => r.predefinedName && r.predefinedName.endsWith(`LogicalResponse`)
65
+ );
66
+ return logicalResponse.length > 0
67
+ ? logicalResponse[0]!.predefinedName!
68
+ : "any";
69
+ }
70
+
62
71
  export function getSendPrivateFunction(
63
72
  dpgContext: SdkContext,
64
73
  operation: Operation,
@@ -109,18 +118,22 @@ export function getDeserializePrivateFunction(
109
118
  runtimeImports: RuntimeImports
110
119
  ): OptionalKind<FunctionDeclarationStructure> {
111
120
  const { name } = getOperationName(operation);
112
-
113
121
  const parameters: OptionalKind<ParameterDeclarationStructure>[] = [
114
122
  {
115
123
  name: "result",
116
124
  type: getRLCResponseType(operation.rlcResponse)
117
125
  }
118
126
  ];
127
+ // TODO: Support LRO + paging operation
128
+ // https://github.com/Azure/autorest.typescript/issues/2313
129
+ const isLroOnly = isLroOnlyOperation(operation);
119
130
 
120
131
  // TODO: Support operation overloads
121
132
  const response = operation.responses[0]!;
122
133
  let returnType;
123
- if (response?.type?.type) {
134
+ if (isLroOnly && operation.method.toLowerCase() !== "patch") {
135
+ returnType = buildLroReturnType(operation);
136
+ } else if (response?.type?.type) {
124
137
  returnType = buildType(
125
138
  response.type.name,
126
139
  response.type,
@@ -166,33 +179,69 @@ export function getDeserializePrivateFunction(
166
179
  }
167
180
  }
168
181
 
169
- const allParents = getAllAncestors(response.type);
170
- const properties = getAllProperties(response.type, allParents) ?? [];
182
+ let deserializedType = isLroOnly
183
+ ? operation?.lroMetadata?.finalResult
184
+ : response.type;
185
+ let hasLroSubPath = operation?.lroMetadata?.finalResultPath !== undefined;
186
+ let deserializedRoot = hasLroSubPath
187
+ ? `result.body.${operation?.lroMetadata?.finalResultPath}`
188
+ : "result.body";
189
+ // TODO: Hard-coded for LRO PATCH case for now
190
+ // https://github.com/Azure/autorest.typescript/issues/2314
191
+ if (isLroOnly && operation.method.toLowerCase() === "patch") {
192
+ deserializedType = response.type;
193
+ hasLroSubPath = false;
194
+ deserializedRoot = "result.body";
195
+ }
196
+ if (isLroOnly) {
197
+ const lroLogicalResponse = getRLCLroLogicalResponse(operation.rlcResponse);
198
+ statements.push(`result = result as ${lroLogicalResponse};`);
199
+ if (hasLroSubPath) {
200
+ statements.push(
201
+ `if(${deserializedRoot.split(".").join("?.")} === undefined) {
202
+ throw createRestError(\`Expected a result in the response at position "${deserializedRoot}"\`, result);
203
+ }
204
+ `
205
+ );
206
+ }
207
+ }
208
+
209
+ const allParents = deserializedType ? getAllAncestors(deserializedType) : [];
210
+ const properties = deserializedType
211
+ ? getAllProperties(deserializedType, allParents)
212
+ : [];
171
213
  if (
172
- response?.type?.type === "any" ||
214
+ deserializedType?.type === "any" ||
215
+ deserializedType?.type === "dict" ||
216
+ (deserializedType?.type === "model" &&
217
+ allParents.some((p) => p.type === "dict")) ||
173
218
  response.isBinaryPayload ||
174
- response?.type?.aliasType
219
+ deserializedType?.aliasType
175
220
  ) {
176
221
  statements.push(`return result.body`);
177
- } else if (properties.length > 0) {
222
+ } else if (deserializedType && properties.length > 0) {
178
223
  statements.push(
179
224
  `return {`,
180
- getResponseMapping(response.type, "result.body", runtimeImports).join(
181
- ","
182
- ),
225
+ getResponseMapping(
226
+ deserializedType,
227
+ deserializedRoot,
228
+ runtimeImports
229
+ ).join(","),
183
230
  `}`
184
231
  );
185
- } else if (returnType.type === "void") {
232
+ } else if (returnType.type === "void" || deserializedType === undefined) {
186
233
  statements.push(`return;`);
187
234
  } else {
188
235
  statements.push(
189
236
  `return ${deserializeResponseValue(
190
- response.type,
191
- "result.body",
237
+ deserializedType,
238
+ deserializedRoot,
192
239
  runtimeImports,
193
- response.type.nullable !== undefined ? !response.type.nullable : false,
194
- [response.type],
195
- response.type.format
240
+ deserializedType.nullable !== undefined
241
+ ? !deserializedType.nullable
242
+ : false,
243
+ [deserializedType],
244
+ deserializedType.format
196
245
  )}`
197
246
  );
198
247
  }
@@ -257,19 +306,115 @@ export function getOperationFunction(
257
306
  operation: Operation,
258
307
  clientType: string
259
308
  ): OptionalKind<FunctionDeclarationStructure> & { propertyName?: string } {
309
+ if (isPagingOnlyOperation(operation)) {
310
+ // Case 1: paging-only operation
311
+ return getPagingOnlyOperationFunction(operation, clientType);
312
+ } else if (isLroOnlyOperation(operation)) {
313
+ // Case 2: lro-only operation
314
+ return getLroOnlyOperationFunction(operation, clientType);
315
+ } else if (isLroAndPagingOperation(operation)) {
316
+ // Case 3: both paging + lro operation is not supported yet so handle them as normal operation and customization may be needed
317
+ // https://github.com/Azure/autorest.typescript/issues/2313
318
+ }
319
+
320
+ // Extract required parameters
321
+ const parameters: OptionalKind<ParameterDeclarationStructure>[] =
322
+ getOperationSignatureParameters(operation, clientType);
323
+ // TODO: Support operation overloads
324
+ const response = operation.responses[0]!;
325
+ let returnType = { name: "", type: "void" };
326
+ if (response.type?.type) {
327
+ const type =
328
+ extractPagingType(response.type, operation.itemName) ?? response.type;
329
+ returnType = buildType(type.name, type, type.format);
330
+ }
331
+ const { name, fixme = [] } = getOperationName(operation);
332
+ const functionStatement = {
333
+ docs: [
334
+ ...getDocsFromDescription(operation.description),
335
+ ...getFixmeForMultilineDocs(fixme)
336
+ ],
337
+ isAsync: true,
338
+ isExported: true,
339
+ name,
340
+ propertyName: operation.name,
341
+ parameters,
342
+ returnType: `Promise<${returnType.type}>`
343
+ };
344
+
345
+ const statements: string[] = [];
346
+ statements.push(
347
+ `const result = await _${name}Send(${parameters
348
+ .map((p) => p.name)
349
+ .join(", ")});`
350
+ );
351
+ statements.push(`return _${name}Deserialize(result);`);
352
+
353
+ return {
354
+ ...functionStatement,
355
+ statements
356
+ };
357
+ }
358
+
359
+ function getLroOnlyOperationFunction(operation: Operation, clientType: string) {
360
+ // Extract required parameters
361
+ const parameters: OptionalKind<ParameterDeclarationStructure>[] =
362
+ getOperationSignatureParameters(operation, clientType);
363
+ const returnType = buildLroReturnType(operation);
364
+ const { name, fixme = [] } = getOperationName(operation);
365
+ const functionStatement = {
366
+ docs: [
367
+ ...getDocsFromDescription(operation.description),
368
+ ...getFixmeForMultilineDocs(fixme)
369
+ ],
370
+ isAsync: false,
371
+ isExported: true,
372
+ name,
373
+ propertyName: operation.name,
374
+ parameters,
375
+ returnType: `PollerLike<OperationState<${returnType.type}>, ${returnType.type}>`
376
+ };
377
+
378
+ const statements: string[] = [];
379
+ statements.push(`
380
+ return getLongRunningPoller(context, _${name}Deserialize, {
381
+ updateIntervalInMs: options?.updateIntervalInMs,
382
+ abortSignal: options?.abortSignal,
383
+ getInitialResponse: () => _${name}Send(${parameters
384
+ .map((p) => p.name)
385
+ .join(", ")})
386
+ }) as PollerLike<OperationState<${returnType.type}>, ${returnType.type}>;
387
+ `);
388
+
389
+ return {
390
+ ...functionStatement,
391
+ statements
392
+ };
393
+ }
394
+
395
+ function buildLroReturnType(operation: Operation) {
396
+ const metadata = operation.lroMetadata;
397
+ if (metadata !== undefined && metadata.finalResult !== undefined) {
398
+ const type = metadata.finalResult;
399
+ return buildType(type.name, type, type.format);
400
+ }
401
+ return { name: "", type: "void" };
402
+ }
403
+
404
+ function getPagingOnlyOperationFunction(
405
+ operation: Operation,
406
+ clientType: string
407
+ ) {
260
408
  // Extract required parameters
261
409
  const parameters: OptionalKind<ParameterDeclarationStructure>[] =
262
410
  getOperationSignatureParameters(operation, clientType);
263
- const isPaging = isPagingOperation(operation);
264
411
 
265
412
  // TODO: Support operation overloads
266
413
  const response = operation.responses[0]!;
267
414
  let returnType = { name: "", type: "void" };
268
415
  if (response.type?.type) {
269
- let type = response.type;
270
- if (isPaging) {
271
- type = extractPagingType(type, operation.itemName) ?? type;
272
- }
416
+ const type =
417
+ extractPagingType(response.type, operation.itemName) ?? response.type;
273
418
  returnType = buildType(type.name, type, type.format);
274
419
  }
275
420
  const { name, fixme = [] } = getOperationName(operation);
@@ -278,41 +423,30 @@ export function getOperationFunction(
278
423
  ...getDocsFromDescription(operation.description),
279
424
  ...getFixmeForMultilineDocs(fixme)
280
425
  ],
281
- isAsync: !isPaging,
426
+ isAsync: false,
282
427
  isExported: true,
283
428
  name,
284
429
  propertyName: operation.name,
285
430
  parameters,
286
- returnType: isPaging
287
- ? `PagedAsyncIterableIterator<${returnType.type}>`
288
- : `Promise<${returnType.type}>`
431
+ returnType: `PagedAsyncIterableIterator<${returnType.type}>`
289
432
  };
290
433
 
291
434
  const statements: string[] = [];
292
- if (isPaging) {
293
- const options = [];
294
- if (operation.itemName) {
295
- options.push(`itemName: "${operation.itemName}"`);
296
- }
297
- if (operation.continuationTokenName) {
298
- options.push(`nextLinkName: "${operation.continuationTokenName}"`);
299
- }
300
- statements.push(
301
- `return buildPagedAsyncIterator(
302
- context,
303
- () => _${name}Send(${parameters.map((p) => p.name).join(", ")}),
304
- _${name}Deserialize,
305
- ${options.length > 0 ? `{${options.join(", ")}}` : ``}
306
- );`
307
- );
308
- } else {
309
- statements.push(
310
- `const result = await _${name}Send(${parameters
311
- .map((p) => p.name)
312
- .join(", ")});`
313
- );
314
- statements.push(`return _${name}Deserialize(result);`);
435
+ const options = [];
436
+ if (operation.itemName) {
437
+ options.push(`itemName: "${operation.itemName}"`);
438
+ }
439
+ if (operation.continuationTokenName) {
440
+ options.push(`nextLinkName: "${operation.continuationTokenName}"`);
315
441
  }
442
+ statements.push(
443
+ `return buildPagedAsyncIterator(
444
+ context,
445
+ () => _${name}Send(${parameters.map((p) => p.name).join(", ")}),
446
+ _${name}Deserialize,
447
+ ${options.length > 0 ? `{${options.join(", ")}}` : ``}
448
+ );`
449
+ );
316
450
 
317
451
  return {
318
452
  ...functionStatement,
@@ -453,7 +587,12 @@ function buildBodyParameter(
453
587
  return "";
454
588
  }
455
589
 
456
- if (bodyParameter.type.type === "model" && !bodyParameter.type.aliasType) {
590
+ const allParents = getAllAncestors(bodyParameter.type);
591
+ if (
592
+ bodyParameter.type.type === "model" &&
593
+ !bodyParameter.type.aliasType &&
594
+ !allParents.some((p) => p.type === "dict")
595
+ ) {
457
596
  const bodyParts: string[] = getRequestModelMapping(
458
597
  bodyParameter.type,
459
598
  bodyParameter.clientName,
@@ -470,8 +609,10 @@ function buildBodyParameter(
470
609
  return `\nbody: ${bodyParameter.clientName},`;
471
610
  }
472
611
  } else if (
473
- bodyParameter.type.type === "model" &&
474
- bodyParameter.type.aliasType
612
+ (bodyParameter.type.type === "model" &&
613
+ (bodyParameter.type.aliasType ||
614
+ allParents.some((p) => p.type === "dict"))) ||
615
+ bodyParameter.type.type === "dict"
475
616
  ) {
476
617
  return `\nbody: ${bodyParameter.clientName},`;
477
618
  }
@@ -790,7 +931,7 @@ export function getRequestModelMapping(
790
931
  const propertyFullName = `${propertyPath}.${property.clientName}`;
791
932
  if (property.type.type === "model") {
792
933
  let definition;
793
- if (property.type.isCoreErrorType) {
934
+ if (property.type.coreTypeInfo === "ErrorType") {
794
935
  definition = `"${property.restApiName}": ${getNullableCheck(
795
936
  propertyFullName,
796
937
  property.type
@@ -885,7 +1026,7 @@ export function getResponseMapping(
885
1026
  const propertyFullName = `${propertyPath}.${property.restApiName}`;
886
1027
  if (property.type.type === "model") {
887
1028
  let definition;
888
- if (property.type.isCoreErrorType) {
1029
+ if (property.type.coreTypeInfo === "ErrorType") {
889
1030
  definition = `"${property.clientName}": ${getNullableCheck(
890
1031
  propertyFullName,
891
1032
  property.type
@@ -1173,29 +1314,23 @@ function needsDeserialize(type?: Type) {
1173
1314
  );
1174
1315
  }
1175
1316
 
1176
- export function hasLROOperation(
1177
- codeModel: ModularCodeModel,
1178
- needRLC: boolean = false
1179
- ) {
1180
- return (codeModel.clients ?? []).some(
1181
- (c) =>
1182
- (needRLC ? c.rlcHelperDetails.hasLongRunning : false) ||
1183
- (c.operationGroups ?? []).some((og) =>
1184
- (og.operations ?? []).some(isLROOperation)
1185
- )
1186
- );
1317
+ export function isLroAndPagingOperation(op: Operation): boolean {
1318
+ return op.discriminator === "lropaging";
1187
1319
  }
1188
1320
 
1189
- export function isLROOperation(op: Operation): boolean {
1190
- return op.discriminator === "lro" || op.discriminator === "lropaging";
1321
+ export function isLroOnlyOperation(op: Operation): boolean {
1322
+ return op.discriminator === "lro";
1191
1323
  }
1192
1324
 
1193
- export function hasPagingOperation(client: Client, needRLC?: boolean): boolean;
1194
- export function hasPagingOperation(
1325
+ export function hasPagingOnlyOperation(
1326
+ client: Client,
1327
+ needRLC?: boolean
1328
+ ): boolean;
1329
+ export function hasPagingOnlyOperation(
1195
1330
  codeModel: ModularCodeModel,
1196
1331
  needRLC?: boolean
1197
1332
  ): boolean;
1198
- export function hasPagingOperation(
1333
+ export function hasPagingOnlyOperation(
1199
1334
  clientOrCodeModel: Client | ModularCodeModel,
1200
1335
  needRLC: boolean = false
1201
1336
  ): boolean {
@@ -1209,13 +1344,13 @@ export function hasPagingOperation(
1209
1344
  (c) =>
1210
1345
  (needRLC ? c.rlcHelperDetails.hasPaging : false) ||
1211
1346
  (c.operationGroups ?? []).some((og) =>
1212
- (og.operations ?? []).some(isPagingOperation)
1347
+ (og.operations ?? []).some(isPagingOnlyOperation)
1213
1348
  )
1214
1349
  );
1215
1350
  }
1216
1351
 
1217
- export function isPagingOperation(op: Operation): boolean {
1218
- return op.discriminator === "paging" || op.discriminator === "lropaging";
1352
+ export function isPagingOnlyOperation(op: Operation): boolean {
1353
+ return op.discriminator === "paging";
1219
1354
  }
1220
1355
 
1221
1356
  export function getAllProperties(type: Type, parents?: Type[]): Property[] {
@@ -30,7 +30,7 @@ const simpleTypeMap: Record<string, TypeMetadata> = {
30
30
  "byte-array": { name: "Uint8Array" },
31
31
  string: { name: "string" },
32
32
  any: { name: "Record<string, any>" },
33
- unknown: { name: "unknown" }
33
+ unknown: { name: "any" }
34
34
  };
35
35
 
36
36
  function handleAnomymousModelName(type: Type) {
@@ -232,7 +232,11 @@ function handleDictType(type: Type): TypeMetadata {
232
232
  if (!type.elementType) {
233
233
  throw new Error("Unable to process dict without elemetType info");
234
234
  }
235
-
235
+ if (type.name && type.name !== "Record") {
236
+ return {
237
+ name: type.name
238
+ };
239
+ }
236
240
  const elementType = getType(type.elementType, type.elementType.format);
237
241
  const elementName = elementType.name;
238
242
  return {
@@ -8,3 +8,9 @@ export interface ClientDetails {
8
8
  baseUrl?: string;
9
9
  credentialsParam?: Parameter;
10
10
  }
11
+
12
+ export interface OperationPathAndDeserDetails {
13
+ path: string;
14
+ deserName: string;
15
+ renamedDeserName?: string;
16
+ }
@@ -6,6 +6,7 @@ import { Project } from "ts-morph";
6
6
 
7
7
  export interface ModularOptions {
8
8
  sourceRoot: string;
9
+ compatibilityMode: boolean;
9
10
  }
10
11
  export interface ModularCodeModel {
11
12
  options: RLCOptions;
@@ -101,7 +102,7 @@ export interface Type {
101
102
  format?: string;
102
103
  properties?: Property[];
103
104
  types?: Type[];
104
- isCoreErrorType?: boolean;
105
+ coreTypeInfo?: "ErrorType" | "LroType";
105
106
  usage?: UsageFlags;
106
107
  alias?: string;
107
108
  aliasType?: string;
@@ -182,4 +183,12 @@ export interface Operation {
182
183
  addedOn?: string;
183
184
  rlcResponse?: OperationResponse;
184
185
  namespaceHierarchies: string[];
186
+ lroMetadata?: LroOperationMetadata;
187
+ }
188
+
189
+ export interface LroOperationMetadata {
190
+ finalStateVia?: string;
191
+ finalResult?: Type;
192
+ /** The path to the field in the 'finalEnvelopeResult' that contains the 'finalResult'. */
193
+ finalResultPath?: string;
185
194
  }
@@ -23,7 +23,7 @@ export function transformHelperFunctionDetails(
23
23
  ): HelperFunctionDetails {
24
24
  const program = dpgContext.program;
25
25
  const serializeInfo = extractSpecialSerializeInfo(client, dpgContext);
26
- // Disbale paging and long running for non-Azure clients.
26
+ // Disable paging and long running for non-Azure clients.
27
27
  if (flavor !== "azure") {
28
28
  return {
29
29
  hasLongRunning: false,
@@ -11,7 +11,7 @@ import {
11
11
  SchemaContext,
12
12
  ApiVersionInfo
13
13
  } from "@azure-tools/rlc-common";
14
- import { ignoreDiagnostics, Type } from "@typespec/compiler";
14
+ import { ignoreDiagnostics, isVoidType, Type } from "@typespec/compiler";
15
15
  import {
16
16
  getHttpOperation,
17
17
  HttpOperation,
@@ -259,7 +259,7 @@ function transformBodyParameters(
259
259
  (parameters.bodyType ?? parameters.bodyParameter?.type) && inputBodyType
260
260
  ? inputBodyType
261
261
  : parameters.bodyType ?? parameters.bodyParameter?.type;
262
- if (!bodyType) {
262
+ if (!bodyType || isVoidType(bodyType)) {
263
263
  return;
264
264
  }
265
265
  return transformRequestBody(
@@ -115,7 +115,7 @@ function transformOperation(
115
115
  responseTypes,
116
116
  operationGroupName
117
117
  ),
118
- isPageable: isPagingOperation(program, route)
118
+ isPaging: isPagingOperation(program, route)
119
119
  }
120
120
  };
121
121
  if (