@azure-tools/typespec-ts 0.14.0 → 0.15.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 (138) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/dist/src/index.d.ts +1 -5
  3. package/dist/src/index.d.ts.map +1 -1
  4. package/dist/src/index.js +148 -78
  5. package/dist/src/index.js.map +1 -1
  6. package/dist/src/lib.d.ts.map +1 -1
  7. package/dist/src/lib.js +4 -2
  8. package/dist/src/lib.js.map +1 -1
  9. package/dist/src/modular/buildClassicalClient.d.ts +1 -1
  10. package/dist/src/modular/buildClassicalClient.d.ts.map +1 -1
  11. package/dist/src/modular/buildClassicalClient.js +7 -6
  12. package/dist/src/modular/buildClassicalClient.js.map +1 -1
  13. package/dist/src/modular/buildClientContext.d.ts +1 -1
  14. package/dist/src/modular/buildClientContext.d.ts.map +1 -1
  15. package/dist/src/modular/buildClientContext.js +16 -7
  16. package/dist/src/modular/buildClientContext.js.map +1 -1
  17. package/dist/src/modular/buildCodeModel.d.ts.map +1 -1
  18. package/dist/src/modular/buildCodeModel.js +6 -6
  19. package/dist/src/modular/buildCodeModel.js.map +1 -1
  20. package/dist/src/modular/buildOperations.d.ts +2 -1
  21. package/dist/src/modular/buildOperations.d.ts.map +1 -1
  22. package/dist/src/modular/buildOperations.js +19 -25
  23. package/dist/src/modular/buildOperations.js.map +1 -1
  24. package/dist/src/modular/buildProjectFiles.d.ts +2 -2
  25. package/dist/src/modular/buildProjectFiles.d.ts.map +1 -1
  26. package/dist/src/modular/buildProjectFiles.js +284 -145
  27. package/dist/src/modular/buildProjectFiles.js.map +1 -1
  28. package/dist/src/modular/buildRootIndex.d.ts.map +1 -1
  29. package/dist/src/modular/buildRootIndex.js +5 -5
  30. package/dist/src/modular/buildRootIndex.js.map +1 -1
  31. package/dist/src/modular/buildSubpathIndex.d.ts.map +1 -1
  32. package/dist/src/modular/buildSubpathIndex.js +9 -2
  33. package/dist/src/modular/buildSubpathIndex.js.map +1 -1
  34. package/dist/src/modular/emitModels.d.ts +2 -1
  35. package/dist/src/modular/emitModels.d.ts.map +1 -1
  36. package/dist/src/modular/emitModels.js +36 -7
  37. package/dist/src/modular/emitModels.js.map +1 -1
  38. package/dist/src/modular/helpers/clientHelpers.d.ts.map +1 -1
  39. package/dist/src/modular/helpers/clientHelpers.js +5 -3
  40. package/dist/src/modular/helpers/clientHelpers.js.map +1 -1
  41. package/dist/src/modular/helpers/docsHelpers.d.ts +3 -0
  42. package/dist/src/modular/helpers/docsHelpers.d.ts.map +1 -0
  43. package/dist/src/modular/helpers/docsHelpers.js +10 -0
  44. package/dist/src/modular/helpers/docsHelpers.js.map +1 -0
  45. package/dist/src/modular/helpers/operationHelpers.d.ts +10 -3
  46. package/dist/src/modular/helpers/operationHelpers.d.ts.map +1 -1
  47. package/dist/src/modular/helpers/operationHelpers.js +162 -35
  48. package/dist/src/modular/helpers/operationHelpers.js.map +1 -1
  49. package/dist/src/modular/helpers/typeHelpers.d.ts.map +1 -1
  50. package/dist/src/modular/helpers/typeHelpers.js +6 -0
  51. package/dist/src/modular/helpers/typeHelpers.js.map +1 -1
  52. package/dist/src/transform/transform.d.ts +5 -8
  53. package/dist/src/transform/transform.d.ts.map +1 -1
  54. package/dist/src/transform/transform.js +23 -13
  55. package/dist/src/transform/transform.js.map +1 -1
  56. package/dist/src/transform/transformApiVersionInfo.d.ts +2 -1
  57. package/dist/src/transform/transformApiVersionInfo.d.ts.map +1 -1
  58. package/dist/src/transform/transformApiVersionInfo.js.map +1 -1
  59. package/dist/src/transform/transformHelperFunctionDetails.d.ts +2 -1
  60. package/dist/src/transform/transformHelperFunctionDetails.d.ts.map +1 -1
  61. package/dist/src/transform/transformHelperFunctionDetails.js +1 -6
  62. package/dist/src/transform/transformHelperFunctionDetails.js.map +1 -1
  63. package/dist/src/transform/transformParameters.d.ts +2 -2
  64. package/dist/src/transform/transformParameters.d.ts.map +1 -1
  65. package/dist/src/transform/transformParameters.js +4 -1
  66. package/dist/src/transform/transformParameters.js.map +1 -1
  67. package/dist/src/transform/transformPaths.d.ts +2 -2
  68. package/dist/src/transform/transformPaths.d.ts.map +1 -1
  69. package/dist/src/transform/transformPaths.js.map +1 -1
  70. package/dist/src/transform/transformResponses.d.ts +2 -2
  71. package/dist/src/transform/transformResponses.d.ts.map +1 -1
  72. package/dist/src/transform/transformResponses.js +5 -1
  73. package/dist/src/transform/transformResponses.js.map +1 -1
  74. package/dist/src/transform/transformSchemas.d.ts +2 -2
  75. package/dist/src/transform/transformSchemas.d.ts.map +1 -1
  76. package/dist/src/transform/transformSchemas.js.map +1 -1
  77. package/dist/src/transform/transformTelemetryInfo.d.ts +4 -0
  78. package/dist/src/transform/transformTelemetryInfo.d.ts.map +1 -0
  79. package/dist/src/transform/transformTelemetryInfo.js +42 -0
  80. package/dist/src/transform/transformTelemetryInfo.js.map +1 -0
  81. package/dist/src/transform/transfromRLCOptions.d.ts +4 -2
  82. package/dist/src/transform/transfromRLCOptions.d.ts.map +1 -1
  83. package/dist/src/transform/transfromRLCOptions.js +27 -13
  84. package/dist/src/transform/transfromRLCOptions.js.map +1 -1
  85. package/dist/src/utils/clientUtils.d.ts +2 -1
  86. package/dist/src/utils/clientUtils.d.ts.map +1 -1
  87. package/dist/src/utils/clientUtils.js.map +1 -1
  88. package/dist/src/utils/interfaces.d.ts +13 -0
  89. package/dist/src/utils/interfaces.d.ts.map +1 -0
  90. package/dist/src/utils/interfaces.js +2 -0
  91. package/dist/src/utils/interfaces.js.map +1 -0
  92. package/dist/src/utils/modelUtils.d.ts +1 -1
  93. package/dist/src/utils/modelUtils.d.ts.map +1 -1
  94. package/dist/src/utils/modelUtils.js +14 -9
  95. package/dist/src/utils/modelUtils.js.map +1 -1
  96. package/dist/src/utils/operationUtil.d.ts +4 -4
  97. package/dist/src/utils/operationUtil.d.ts.map +1 -1
  98. package/dist/src/utils/operationUtil.js +1 -1
  99. package/dist/src/utils/operationUtil.js.map +1 -1
  100. package/dist/tsconfig.tsbuildinfo +1 -1
  101. package/package.json +28 -18
  102. package/src/index.ts +231 -129
  103. package/src/lib.ts +4 -2
  104. package/src/modular/buildClassicalClient.ts +10 -7
  105. package/src/modular/buildClientContext.ts +18 -8
  106. package/src/modular/buildCodeModel.ts +7 -9
  107. package/src/modular/buildOperations.ts +25 -32
  108. package/src/modular/buildProjectFiles.ts +329 -162
  109. package/src/modular/buildRootIndex.ts +5 -7
  110. package/src/modular/buildSubpathIndex.ts +9 -2
  111. package/src/modular/emitModels.ts +47 -5
  112. package/src/modular/helpers/clientHelpers.ts +5 -3
  113. package/src/modular/helpers/docsHelpers.ts +10 -0
  114. package/src/modular/helpers/operationHelpers.ts +277 -36
  115. package/src/modular/helpers/typeHelpers.ts +6 -0
  116. package/src/transform/transform.ts +24 -31
  117. package/src/transform/transformApiVersionInfo.ts +1 -1
  118. package/src/transform/transformHelperFunctionDetails.ts +2 -7
  119. package/src/transform/transformParameters.ts +15 -12
  120. package/src/transform/transformPaths.ts +5 -5
  121. package/src/transform/transformResponses.ts +10 -6
  122. package/src/transform/transformSchemas.ts +2 -2
  123. package/src/transform/transformTelemetryInfo.ts +72 -0
  124. package/src/transform/transfromRLCOptions.ts +34 -15
  125. package/src/utils/clientUtils.ts +2 -4
  126. package/src/utils/interfaces.ts +14 -0
  127. package/src/utils/modelUtils.ts +17 -8
  128. package/src/utils/operationUtil.ts +5 -6
  129. package/dist/src/modular/helpers/fixmeHelpers.d.ts +0 -2
  130. package/dist/src/modular/helpers/fixmeHelpers.d.ts.map +0 -1
  131. package/dist/src/modular/helpers/fixmeHelpers.js +0 -4
  132. package/dist/src/modular/helpers/fixmeHelpers.js.map +0 -1
  133. package/dist/src/modular/helpers/parameterHelpers.d.ts +0 -3
  134. package/dist/src/modular/helpers/parameterHelpers.d.ts.map +0 -1
  135. package/dist/src/modular/helpers/parameterHelpers.js +0 -16
  136. package/dist/src/modular/helpers/parameterHelpers.js.map +0 -1
  137. package/src/modular/helpers/fixmeHelpers.ts +0 -3
  138. package/src/modular/helpers/parameterHelpers.ts +0 -17
@@ -1,7 +1,9 @@
1
1
  import { Project, SourceFile } from "ts-morph";
2
2
  import { getType } from "./helpers/typeHelpers.js";
3
- import { ModularCodeModel, Type } from "./modularCodeModel.js";
3
+ import { Client, ModularCodeModel, Type } from "./modularCodeModel.js";
4
4
  import * as path from "path";
5
+ import { getDocsFromDescription } from "./helpers/docsHelpers.js";
6
+ import { buildOperationOptions } from "./buildOperations.js";
5
7
 
6
8
  /**
7
9
  * This function creates the file containing all the models defined in TypeSpec
@@ -13,7 +15,7 @@ export function buildModels(
13
15
  subfolder: string = ""
14
16
  ): SourceFile {
15
17
  const modelsFile = project.createSourceFile(
16
- path.join(`${srcPath}/src/`, subfolder, `models/models.ts`)
18
+ path.join(`${srcPath}/`, subfolder, `models/models.ts`)
17
19
  );
18
20
 
19
21
  // We are generating both models and enums here
@@ -48,7 +50,7 @@ export function buildModels(
48
50
  name: model.name!,
49
51
  isExported: true,
50
52
  docs: [
51
- model.description ?? "",
53
+ ...getDocsFromDescription(model.description),
52
54
  // If it is a fixed enum we don't need to list the known values in the docs as the
53
55
  // output will be a literal union which is self documenting
54
56
  model.isFixed
@@ -68,7 +70,7 @@ export function buildModels(
68
70
  modelsFile.addInterface({
69
71
  name: model.name,
70
72
  isExported: true,
71
- docs: [model.description ?? ""],
73
+ docs: getDocsFromDescription(model.description),
72
74
  properties: properties.map((p) => {
73
75
  const propertyMetadata = getType(p.type);
74
76
  let propertyTypeName = propertyMetadata.name;
@@ -82,7 +84,7 @@ export function buildModels(
82
84
  }
83
85
  return {
84
86
  name: `"${p.clientName}"`,
85
- docs: [p.description],
87
+ docs: getDocsFromDescription(p.description),
86
88
  hasQuestionToken: p.optional,
87
89
  isReadonly: p.readonly,
88
90
  type: propertyTypeName
@@ -117,3 +119,43 @@ function isAzureCoreError(t: Type) {
117
119
  t.isCoreErrorType === true
118
120
  );
119
121
  }
122
+
123
+ export function buildModelsOptions(
124
+ client: Client,
125
+ project: Project,
126
+ srcPath: string = "src",
127
+ subfolder: string = ""
128
+ ) {
129
+ const modelOptionsFile = project.createSourceFile(
130
+ `${srcPath}/${subfolder}/models/options.ts`,
131
+ undefined,
132
+ {
133
+ overwrite: true
134
+ }
135
+ );
136
+ for (const operationGroup of client.operationGroups) {
137
+ operationGroup.operations.forEach((o) => {
138
+ buildOperationOptions(o, modelOptionsFile);
139
+ });
140
+ }
141
+ modelOptionsFile.addImportDeclarations([
142
+ {
143
+ moduleSpecifier: "@azure-rest/core-client",
144
+ namedImports: ["OperationOptions"]
145
+ }
146
+ ]);
147
+
148
+ modelOptionsFile.fixMissingImports();
149
+ modelOptionsFile
150
+ .getImportDeclarations()
151
+ .filter((id) => {
152
+ return (
153
+ id.isModuleSpecifierRelative() &&
154
+ !id.getModuleSpecifierValue().endsWith(".js")
155
+ );
156
+ })
157
+ .map((id) => {
158
+ id.setModuleSpecifier(id.getModuleSpecifierValue() + ".js");
159
+ return id;
160
+ });
161
+ }
@@ -1,11 +1,13 @@
1
1
  import { OptionalKind, ParameterDeclarationStructure } from "ts-morph";
2
2
  import { Client } from "../modularCodeModel.js";
3
- import { getParameterType } from "./parameterHelpers.js";
3
+ import { getType } from "./typeHelpers.js";
4
+ import { getClientName } from "./namingHelpers.js";
4
5
 
5
6
  export function getClientParameters(
6
7
  client: Client
7
8
  ): OptionalKind<ParameterDeclarationStructure>[] {
8
- const { name, parameters } = client;
9
+ const { parameters } = client;
10
+ const name = getClientName(client);
9
11
  const optionsParam = {
10
12
  name: "options",
11
13
  type: `${name}ClientOptions`,
@@ -22,7 +24,7 @@ export function getClientParameters(
22
24
  .map<OptionalKind<ParameterDeclarationStructure>>((p) => {
23
25
  return {
24
26
  name: p.clientName,
25
- type: getParameterType(p)
27
+ type: getType(p.type).name
26
28
  };
27
29
  }),
28
30
  optionsParam
@@ -0,0 +1,10 @@
1
+ export function getFixmeForMultilineDocs(fixme: string[]): string[] {
2
+ return fixme.map((fixme) => ` @fixme ${fixme}`);
3
+ }
4
+
5
+ export function getDocsFromDescription(description?: string): string[] {
6
+ if (!description || description.trim().length === 0) {
7
+ return [];
8
+ }
9
+ return [description];
10
+ }
@@ -6,6 +6,7 @@ import {
6
6
  import { toPascalCase } from "../../utils/casingUtils.js";
7
7
  import {
8
8
  BodyParameter,
9
+ ModularCodeModel,
9
10
  Operation,
10
11
  Parameter,
11
12
  Property,
@@ -20,7 +21,10 @@ import {
20
21
  normalizeName
21
22
  } from "@azure-tools/rlc-common";
22
23
  import { getOperationName } from "./namingHelpers.js";
23
- import { getFixmeForMultilineDocs } from "./fixmeHelpers.js";
24
+ import {
25
+ getFixmeForMultilineDocs,
26
+ getDocsFromDescription
27
+ } from "./docsHelpers.js";
24
28
 
25
29
  function getRLCResponseType(rlcResponse?: OperationResponse) {
26
30
  if (!rlcResponse?.responses) {
@@ -41,11 +45,9 @@ function getRLCResponseType(rlcResponse?: OperationResponse) {
41
45
 
42
46
  export function getSendPrivateFunction(
43
47
  operation: Operation,
44
- clientType: string
48
+ clientType: string,
49
+ importSet: Map<string, Set<string>>
45
50
  ): OptionalKind<FunctionDeclarationStructure> {
46
- if (operation.name === "uploadTestFile") {
47
- operation;
48
- }
49
51
  const parameters = getOperationSignatureParameters(operation, clientType);
50
52
  const { name } = getOperationName(operation);
51
53
 
@@ -65,7 +67,8 @@ export function getSendPrivateFunction(
65
67
  `return context.path("${operationPath}", ${getPathParameters(
66
68
  operation
67
69
  )}).${operationMethod}({...operationOptionsToRequestParameters(options), ${getRequestParameters(
68
- operation
70
+ operation,
71
+ importSet
69
72
  )}});`
70
73
  );
71
74
 
@@ -78,7 +81,8 @@ export function getSendPrivateFunction(
78
81
  export function getDeserializePrivateFunction(
79
82
  operation: Operation,
80
83
  needSubClient: boolean,
81
- needUnexpectedHelper: boolean
84
+ needUnexpectedHelper: boolean,
85
+ importSet: Map<string, Set<string>>
82
86
  ): OptionalKind<FunctionDeclarationStructure> {
83
87
  const { name } = getOperationName(operation);
84
88
 
@@ -126,12 +130,21 @@ export function getDeserializePrivateFunction(
126
130
  statements.push(`return result.body`);
127
131
  } else if (response?.type?.elementType) {
128
132
  statements.push(
129
- `return ${deserializeResponseValue(response.type, "result.body")}`
133
+ `return ${deserializeResponseValue(
134
+ response.type,
135
+ "result.body",
136
+ importSet,
137
+ response.type.nullable !== undefined ? !response.type.nullable : false
138
+ )}`
130
139
  );
131
140
  } else if (response?.type?.properties) {
132
141
  statements.push(
133
142
  `return {`,
134
- getResponseMapping(response.type.properties ?? []).join(","),
143
+ getResponseMapping(
144
+ response.type.properties ?? [],
145
+ "result.body",
146
+ importSet
147
+ ).join(","),
135
148
  `}`
136
149
  );
137
150
  } else if (returnType.type === "void") {
@@ -223,7 +236,10 @@ export function getOperationFunction(
223
236
 
224
237
  const { name, fixme = [] } = getOperationName(operation);
225
238
  const functionStatement: OptionalKind<FunctionDeclarationStructure> = {
226
- docs: [operation.description, ...getFixmeForMultilineDocs(fixme)],
239
+ docs: [
240
+ ...getDocsFromDescription(operation.description),
241
+ ...getFixmeForMultilineDocs(fixme)
242
+ ],
227
243
  isAsync: true,
228
244
  isExported: true,
229
245
  name: normalizeName(operation.name, NameType.Operation, true),
@@ -255,7 +271,10 @@ export function getOperationOptionsName(operation: Operation) {
255
271
  * RLC internally. This will translate High Level parameters into the RLC ones.
256
272
  * Figuring out what goes in headers, body, path and qsp.
257
273
  */
258
- function getRequestParameters(operation: Operation): string {
274
+ function getRequestParameters(
275
+ operation: Operation,
276
+ importSet: Map<string, Set<string>>
277
+ ): string {
259
278
  if (!operation.parameters) {
260
279
  return "";
261
280
  }
@@ -277,7 +296,9 @@ function getRequestParameters(operation: Operation): string {
277
296
 
278
297
  for (const param of operationParameters) {
279
298
  if (param.location === "header" || param.location === "query") {
280
- parametersImplementation[param.location].push(getParameterMap(param));
299
+ parametersImplementation[param.location].push(
300
+ getParameterMap(param, importSet)
301
+ );
281
302
  }
282
303
  }
283
304
 
@@ -299,30 +320,60 @@ function getRequestParameters(operation: Operation): string {
299
320
  )}},`;
300
321
  }
301
322
 
302
- paramStr = `${paramStr}${buildBodyParameter(operation.bodyParameter)}`;
323
+ paramStr = `${paramStr}${buildBodyParameter(
324
+ operation.bodyParameter,
325
+ importSet
326
+ )}`;
303
327
 
304
328
  return paramStr;
305
329
  }
306
330
 
307
- function buildBodyParameter(bodyParameter: BodyParameter | undefined) {
331
+ function buildBodyParameter(
332
+ bodyParameter: BodyParameter | undefined,
333
+ importSet: Map<string, Set<string>>
334
+ ) {
308
335
  if (!bodyParameter) {
309
336
  return "";
310
337
  }
311
338
 
312
339
  if (bodyParameter.type.type === "model") {
313
340
  const bodyParts: string[] = [];
341
+ let hasSerializeBody = false;
314
342
  for (const param of bodyParameter?.type.properties?.filter(
315
343
  (p) => !p.readonly
316
344
  ) ?? []) {
317
- bodyParts.push(getParameterMap(param));
345
+ if (param.type.type === "model" && isRequired(param)) {
346
+ hasSerializeBody = true;
347
+ bodyParts.push(
348
+ ...getRequestModelMapping(param.type, param.clientName, importSet)
349
+ );
350
+ } else {
351
+ bodyParts.push(getParameterMap(param, importSet));
352
+ }
318
353
  }
319
354
 
320
355
  if (bodyParameter && bodyParameter.type.properties) {
321
- return `\nbody: {${bodyParts.join(",\n")}},`;
356
+ if (hasSerializeBody) {
357
+ return `\nbody: {"${bodyParameter.restApiName}": {${bodyParts.join(
358
+ ",\n"
359
+ )}}},`;
360
+ } else {
361
+ return `\nbody: {${bodyParts.join(",\n")}},`;
362
+ }
322
363
  }
323
364
  }
324
365
 
325
366
  if (bodyParameter.type.type === "list") {
367
+ if (bodyParameter.type.elementType?.type === "model") {
368
+ const bodyParts = getRequestModelMapping(
369
+ bodyParameter.type.elementType,
370
+ "p",
371
+ importSet
372
+ );
373
+ return `\nbody: (${bodyParameter.clientName} ?? []).map((p) => { return {
374
+ ${bodyParts.join(", ")}
375
+ };}),`;
376
+ }
326
377
  return `\nbody: ${bodyParameter.clientName},`;
327
378
  }
328
379
 
@@ -336,21 +387,24 @@ function buildBodyParameter(bodyParameter: BodyParameter | undefined) {
336
387
  /**
337
388
  * This function helps with renames, translating client names to rest api names
338
389
  */
339
- function getParameterMap(param: Parameter | Property) {
390
+ function getParameterMap(
391
+ param: Parameter | Property,
392
+ importSet: Map<string, Set<string>>
393
+ ): string {
340
394
  if (isConstant(param)) {
341
395
  return getConstantValue(param);
342
396
  }
343
397
 
344
398
  if (isOptionalWithouDefault(param)) {
345
- return getOptionalWithoutDefault(param);
399
+ return getOptionalWithoutDefault(param, importSet);
346
400
  }
347
401
 
348
402
  if (isOptionalWithDefault(param)) {
349
- return getOptionalWithDefault(param);
403
+ return getOptionalWithDefault(param, importSet);
350
404
  }
351
405
 
352
406
  if (isRequired(param)) {
353
- return getRequired(param);
407
+ return getRequired(param, importSet);
354
408
  }
355
409
 
356
410
  throw new Error(`Parameter ${param.clientName} is not supported`);
@@ -388,7 +442,14 @@ function isRequired(param: Parameter | Property): param is RequiredType {
388
442
  return !param.optional;
389
443
  }
390
444
 
391
- function getRequired(param: RequiredType) {
445
+ function getRequired(param: RequiredType, importSet: Map<string, Set<string>>) {
446
+ if (param.type.type === "model") {
447
+ return `"${param.restApiName}": ${getRequestModelMapping(
448
+ param.type,
449
+ param.clientName,
450
+ importSet
451
+ ).join(",")}`;
452
+ }
392
453
  return `"${param.restApiName}": ${param.clientName}`;
393
454
  }
394
455
 
@@ -423,7 +484,17 @@ function isOptionalWithouDefault(
423
484
  ): param is OptionalWithoutDefaultType {
424
485
  return Boolean(param.optional && !param.clientDefaultValue);
425
486
  }
426
- function getOptionalWithoutDefault(param: OptionalWithoutDefaultType) {
487
+ function getOptionalWithoutDefault(
488
+ param: OptionalWithoutDefaultType,
489
+ importSet: Map<string, Set<string>>
490
+ ) {
491
+ if (param.type.type === "model") {
492
+ return `"${param.restApiName}": {${getRequestModelMapping(
493
+ param.type,
494
+ "options?." + param.clientName + "?",
495
+ importSet
496
+ ).join(", ")}}`;
497
+ }
427
498
  return `"${param.restApiName}": options?.${param.clientName}`;
428
499
  }
429
500
 
@@ -436,7 +507,17 @@ function isOptionalWithDefault(
436
507
  return Boolean(param.clientDefaultValue);
437
508
  }
438
509
 
439
- function getOptionalWithDefault(param: OptionalWithDefaultType) {
510
+ function getOptionalWithDefault(
511
+ param: OptionalWithDefaultType,
512
+ importSet: Map<string, Set<string>>
513
+ ) {
514
+ if (param.type.type === "model") {
515
+ return `"${param.restApiName}": {${getRequestModelMapping(
516
+ param.type,
517
+ "options?." + param.clientName,
518
+ importSet
519
+ ).join(", ")}} ?? ${getQuotedValue(param)}`;
520
+ }
440
521
  return `"${param.restApiName}": options.${
441
522
  param.clientName
442
523
  } ?? ${getQuotedValue(param)}`;
@@ -500,29 +581,94 @@ function getNullableCheck(name: string, type: Type) {
500
581
 
501
582
  return `${name} === null ? null :`;
502
583
  }
584
+
585
+ /**
586
+ *
587
+ * This function helps translating an HLC request to RLC request,
588
+ * extracting properties from body and headers and building the RLC response object
589
+ */
590
+ function getRequestModelMapping(
591
+ modelPropertyType: Type,
592
+ propertyPath: string = "body",
593
+ importSet: Map<string, Set<string>>
594
+ ) {
595
+ if (!modelPropertyType.properties || !modelPropertyType.properties) {
596
+ return [];
597
+ }
598
+ const props: string[] = [];
599
+ const properties: Property[] = modelPropertyType.properties;
600
+ for (const property of properties) {
601
+ if (property.readonly) {
602
+ continue;
603
+ }
604
+ const propertyFullName = `${propertyPath}.${property.restApiName}`;
605
+ if (property.type.type === "model") {
606
+ let definition;
607
+ if (property.type.isCoreErrorType) {
608
+ definition = `"${property.restApiName}": ${getNullableCheck(
609
+ propertyFullName,
610
+ property.type
611
+ )} ${
612
+ !property.optional ? "" : `!${propertyFullName} ? undefined :`
613
+ } ${propertyFullName}`;
614
+ } else {
615
+ definition = `"${property.restApiName}": ${getNullableCheck(
616
+ propertyFullName,
617
+ property.type
618
+ )} ${
619
+ !property.optional ? "" : `!${propertyFullName} ? undefined :`
620
+ } {${getRequestModelMapping(
621
+ property.type,
622
+ `${propertyPath}.${property.restApiName}${
623
+ property.optional ? "?" : ""
624
+ }`,
625
+ importSet
626
+ )}}`;
627
+ }
628
+
629
+ props.push(definition);
630
+ } else {
631
+ const dot = propertyPath.endsWith("?") ? "." : "";
632
+ const restValue = `${
633
+ propertyPath ? `${propertyPath}${dot}` : `${dot}`
634
+ }["${property.clientName}"]`;
635
+ props.push(
636
+ `"${property.restApiName}": ${serializeRequestValue(
637
+ property.type,
638
+ restValue,
639
+ importSet
640
+ )}`
641
+ );
642
+ }
643
+ }
644
+
645
+ return props;
646
+ }
647
+
503
648
  /**
504
649
  * This function helps translating an RLC response to an HLC response,
505
650
  * extracting properties from body and headers and building the HLC response object
506
651
  */
507
- function getResponseMapping(
652
+ export function getResponseMapping(
508
653
  properties: Property[],
509
- propertyPath: string = "result.body"
654
+ propertyPath: string = "result.body",
655
+ importSet: Map<string, Set<string>>
510
656
  ) {
511
657
  const props: string[] = [];
512
658
  for (const property of properties) {
513
659
  // TODO: Do we need to also add headers in the result type?
514
- const propertyFullName = `${propertyPath}.${property.clientName}`;
660
+ const propertyFullName = `${propertyPath}.${property.restApiName}`;
515
661
  if (property.type.type === "model") {
516
662
  let definition;
517
663
  if (property.type.isCoreErrorType) {
518
- definition = `"${property.restApiName}": ${getNullableCheck(
664
+ definition = `"${property.clientName}": ${getNullableCheck(
519
665
  propertyFullName,
520
666
  property.type
521
667
  )} ${
522
668
  !property.optional ? "" : `!${propertyFullName} ? undefined :`
523
669
  } ${propertyFullName}`;
524
670
  } else {
525
- definition = `"${property.restApiName}": ${getNullableCheck(
671
+ definition = `"${property.clientName}": ${getNullableCheck(
526
672
  propertyFullName,
527
673
  property.type
528
674
  )} ${
@@ -531,7 +677,8 @@ function getResponseMapping(
531
677
  property.type.properties ?? [],
532
678
  `${propertyPath}.${property.restApiName}${
533
679
  property.optional ? "?" : ""
534
- }`
680
+ }`,
681
+ importSet
535
682
  )}}`;
536
683
  }
537
684
 
@@ -544,7 +691,9 @@ function getResponseMapping(
544
691
  props.push(
545
692
  `"${property.clientName}": ${deserializeResponseValue(
546
693
  property.type,
547
- restValue
694
+ restValue,
695
+ importSet,
696
+ property.optional !== undefined ? !property.optional : false
548
697
  )}`
549
698
  );
550
699
  }
@@ -558,29 +707,100 @@ function getResponseMapping(
558
707
  * We need to drill down into Array elements to make sure that the element type is
559
708
  * deserialized correctly
560
709
  */
561
- function deserializeResponseValue(type: Type, restValue: string): string {
710
+ function deserializeResponseValue(
711
+ type: Type,
712
+ restValue: string,
713
+ importSet: Map<string, Set<string>>,
714
+ required: boolean
715
+ ): string {
716
+ const coreUtilSet = importSet.get("@azure/core-util");
562
717
  switch (type.type) {
563
718
  case "datetime":
564
- return `new Date(${restValue} ?? "")`;
565
- case "byte-array":
566
- return `Buffer.from(${restValue} ?? "")`;
719
+ return required
720
+ ? `new Date(${restValue})`
721
+ : `${restValue} !== undefined? new Date(${restValue}): undefined`;
722
+ case "combined":
723
+ return `${restValue} as any`;
567
724
  case "list":
568
725
  if (type.elementType?.type === "model") {
569
726
  return `(${restValue} ?? []).map(p => ({${getResponseMapping(
570
727
  type.elementType?.properties ?? [],
571
- "p"
728
+ "p",
729
+ importSet
572
730
  )}}))`;
573
731
  } else if (
574
732
  type.elementType?.properties?.some((p) => needsDeserialize(p.type))
575
733
  ) {
576
734
  return `(${restValue} ?? []).map(p => ${deserializeResponseValue(
577
735
  type.elementType!,
578
- "p"
736
+ "p",
737
+ importSet,
738
+ required
579
739
  )})`;
580
740
  } else {
581
741
  return restValue;
582
742
  }
743
+ case "byte-array":
744
+ if (!coreUtilSet) {
745
+ importSet.set(
746
+ "@azure/core-util",
747
+ new Set<string>().add("stringToUint8Array")
748
+ );
749
+ } else {
750
+ coreUtilSet.add("stringToUint8Array");
751
+ }
752
+ return `typeof ${restValue} === 'string'
753
+ ? stringToUint8Array(${restValue}, "${type.format ?? "base64"}")
754
+ : ${restValue}`;
755
+ default:
756
+ return restValue;
757
+ }
758
+ }
583
759
 
760
+ /**
761
+ * This function helps converting strings into JS complex types recursively.
762
+ * We need to drill down into Array elements to make sure that the element type is
763
+ * deserialized correctly
764
+ */
765
+ function serializeRequestValue(
766
+ type: Type,
767
+ restValue: string,
768
+ importSet: Map<string, Set<string>> = new Map<string, Set<string>>()
769
+ ): string {
770
+ const coreUtilSet = importSet.get("@azure/core-util");
771
+ switch (type.type) {
772
+ case "datetime":
773
+ return `${restValue} !== undefined ? new Date(${restValue}): undefined`;
774
+ case "list":
775
+ if (type.elementType?.type === "model") {
776
+ return `(${restValue} ?? []).map(p => ({${getResponseMapping(
777
+ type.elementType?.properties ?? [],
778
+ "p",
779
+ importSet
780
+ )}}))`;
781
+ } else if (
782
+ type.elementType?.properties?.some((p) => needsDeserialize(p.type))
783
+ ) {
784
+ return `(${restValue} ?? []).map(p => ${serializeRequestValue(
785
+ type.elementType!,
786
+ "p",
787
+ importSet
788
+ )})`;
789
+ } else {
790
+ return restValue;
791
+ }
792
+ case "byte-array":
793
+ if (!coreUtilSet) {
794
+ importSet.set(
795
+ "@azure/core-util",
796
+ new Set<string>().add("uint8ArrayToString")
797
+ );
798
+ } else {
799
+ coreUtilSet.add("uint8ArrayToString");
800
+ }
801
+ return `${restValue} !== undefined ? uint8ArrayToString(${restValue}, "${
802
+ type.format ?? "base64"
803
+ }"): undefined`;
584
804
  default:
585
805
  return restValue;
586
806
  }
@@ -589,3 +809,24 @@ function deserializeResponseValue(type: Type, restValue: string): string {
589
809
  function needsDeserialize(type?: Type) {
590
810
  return type?.type === "datetime" || type?.type === "model";
591
811
  }
812
+
813
+ export function hasLROOperation(codeModel: ModularCodeModel) {
814
+ return (codeModel.clients ?? []).some((c) =>
815
+ (c.operationGroups ?? []).some((og) =>
816
+ (og.operations ?? []).some(
817
+ (op) => op.discriminator === "lro" || op.discriminator === "lropaging"
818
+ )
819
+ )
820
+ );
821
+ }
822
+
823
+ export function hasPagingOperation(codeModel: ModularCodeModel) {
824
+ return (codeModel.clients ?? []).some((c) =>
825
+ (c.operationGroups ?? []).some((og) =>
826
+ (og.operations ?? []).some(
827
+ (op) =>
828
+ op.discriminator === "paging" || op.discriminator === "lropaging"
829
+ )
830
+ )
831
+ );
832
+ }
@@ -23,6 +23,12 @@ export function getType(type: Type): TypeMetadata {
23
23
  originModule: "@azure/core-auth",
24
24
  isRelative: false
25
25
  };
26
+ case "OAuth2":
27
+ return {
28
+ name: "TokenCredential",
29
+ originModule: "@azure/core-auth",
30
+ isRelative: false
31
+ };
26
32
  case "boolean":
27
33
  return { name: getNullableType(type.type, type) };
28
34
  case "constant": {