@azure-tools/rlc-common 0.11.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 (232) hide show
  1. package/.eslintrc.json +23 -0
  2. package/.prettierignore +1 -0
  3. package/.prettierrc +7 -0
  4. package/.rush/temp/package-deps_build.json +53 -0
  5. package/.rush/temp/shrinkwrap-deps.json +147 -0
  6. package/CHANGELOG.md +61 -0
  7. package/CONTRIBUTING.md +30 -0
  8. package/README.md +3 -0
  9. package/dist/buildClient.js +268 -0
  10. package/dist/buildClient.js.map +1 -0
  11. package/dist/buildClientDefinitions.js +160 -0
  12. package/dist/buildClientDefinitions.js.map +1 -0
  13. package/dist/buildIndexFile.js +170 -0
  14. package/dist/buildIndexFile.js.map +1 -0
  15. package/dist/buildIsUnexpectedHelper.js +220 -0
  16. package/dist/buildIsUnexpectedHelper.js.map +1 -0
  17. package/dist/buildMethodShortcuts.js +50 -0
  18. package/dist/buildMethodShortcuts.js.map +1 -0
  19. package/dist/buildObjectTypes.js +286 -0
  20. package/dist/buildObjectTypes.js.map +1 -0
  21. package/dist/buildPaginateHelper.js +30 -0
  22. package/dist/buildPaginateHelper.js.map +1 -0
  23. package/dist/buildParameterTypes.js +315 -0
  24. package/dist/buildParameterTypes.js.map +1 -0
  25. package/dist/buildPollingHelper.js +21 -0
  26. package/dist/buildPollingHelper.js.map +1 -0
  27. package/dist/buildResponseTypes.js +135 -0
  28. package/dist/buildResponseTypes.js.map +1 -0
  29. package/dist/buildSchemaType.js +65 -0
  30. package/dist/buildSchemaType.js.map +1 -0
  31. package/dist/buildSerializeHelper.js +35 -0
  32. package/dist/buildSerializeHelper.js.map +1 -0
  33. package/dist/buildTopLevelIndexFile.js +48 -0
  34. package/dist/buildTopLevelIndexFile.js.map +1 -0
  35. package/dist/helpers/nameConstructors.js +41 -0
  36. package/dist/helpers/nameConstructors.js.map +1 -0
  37. package/dist/helpers/nameUtils.js +196 -0
  38. package/dist/helpers/nameUtils.js.map +1 -0
  39. package/dist/helpers/operationHelpers.js +103 -0
  40. package/dist/helpers/operationHelpers.js.map +1 -0
  41. package/dist/helpers/pathUtils.js +13 -0
  42. package/dist/helpers/pathUtils.js.map +1 -0
  43. package/dist/helpers/schemaHelpers.js +27 -0
  44. package/dist/helpers/schemaHelpers.js.map +1 -0
  45. package/dist/helpers/shortcutMethods.js +46 -0
  46. package/dist/helpers/shortcutMethods.js.map +1 -0
  47. package/dist/index.js +45 -0
  48. package/dist/index.js.map +1 -0
  49. package/dist/interfaces.js +18 -0
  50. package/dist/interfaces.js.map +1 -0
  51. package/dist/metadata/buildApiExtractorConfig.js +56 -0
  52. package/dist/metadata/buildApiExtractorConfig.js.map +1 -0
  53. package/dist/metadata/buildESLintConfig.js +33 -0
  54. package/dist/metadata/buildESLintConfig.js.map +1 -0
  55. package/dist/metadata/buildLicenseFile.js +41 -0
  56. package/dist/metadata/buildLicenseFile.js.map +1 -0
  57. package/dist/metadata/buildPackageFile.js +274 -0
  58. package/dist/metadata/buildPackageFile.js.map +1 -0
  59. package/dist/metadata/buildReadmeFile.js +170 -0
  60. package/dist/metadata/buildReadmeFile.js.map +1 -0
  61. package/dist/metadata/buildRollupConfig.js +144 -0
  62. package/dist/metadata/buildRollupConfig.js.map +1 -0
  63. package/dist/metadata/buildTsConfig.js +72 -0
  64. package/dist/metadata/buildTsConfig.js.map +1 -0
  65. package/dist/package.json +1 -0
  66. package/dist/static/paginateContent.js +214 -0
  67. package/dist/static/paginateContent.js.map +1 -0
  68. package/dist/static/pollingContent.js +98 -0
  69. package/dist/static/pollingContent.js.map +1 -0
  70. package/dist/static/serializeHelper.js +30 -0
  71. package/dist/static/serializeHelper.js.map +1 -0
  72. package/dist/test/buildEnvFile.js +31 -0
  73. package/dist/test/buildEnvFile.js.map +1 -0
  74. package/dist/test/buildKarmaConfig.js +19 -0
  75. package/dist/test/buildKarmaConfig.js.map +1 -0
  76. package/dist/test/buildRecordedClient.js +22 -0
  77. package/dist/test/buildRecordedClient.js.map +1 -0
  78. package/dist/test/buildSampleTest.js +19 -0
  79. package/dist/test/buildSampleTest.js.map +1 -0
  80. package/dist/test/template.js +191 -0
  81. package/dist/test/template.js.map +1 -0
  82. package/dist-esm/buildClient.js +261 -0
  83. package/dist-esm/buildClient.js.map +1 -0
  84. package/dist-esm/buildClientDefinitions.js +155 -0
  85. package/dist-esm/buildClientDefinitions.js.map +1 -0
  86. package/dist-esm/buildIndexFile.js +165 -0
  87. package/dist-esm/buildIndexFile.js.map +1 -0
  88. package/dist-esm/buildIsUnexpectedHelper.js +216 -0
  89. package/dist-esm/buildIsUnexpectedHelper.js.map +1 -0
  90. package/dist-esm/buildMethodShortcuts.js +46 -0
  91. package/dist-esm/buildMethodShortcuts.js.map +1 -0
  92. package/dist-esm/buildObjectTypes.js +288 -0
  93. package/dist-esm/buildObjectTypes.js.map +1 -0
  94. package/dist-esm/buildPaginateHelper.js +26 -0
  95. package/dist-esm/buildPaginateHelper.js.map +1 -0
  96. package/dist-esm/buildParameterTypes.js +321 -0
  97. package/dist-esm/buildParameterTypes.js.map +1 -0
  98. package/dist-esm/buildPollingHelper.js +17 -0
  99. package/dist-esm/buildPollingHelper.js.map +1 -0
  100. package/dist-esm/buildResponseTypes.js +140 -0
  101. package/dist-esm/buildResponseTypes.js.map +1 -0
  102. package/dist-esm/buildSchemaType.js +60 -0
  103. package/dist-esm/buildSchemaType.js.map +1 -0
  104. package/dist-esm/buildSerializeHelper.js +31 -0
  105. package/dist-esm/buildSerializeHelper.js.map +1 -0
  106. package/dist-esm/buildTopLevelIndexFile.js +44 -0
  107. package/dist-esm/buildTopLevelIndexFile.js.map +1 -0
  108. package/dist-esm/helpers/nameConstructors.js +34 -0
  109. package/dist-esm/helpers/nameConstructors.js.map +1 -0
  110. package/dist-esm/helpers/nameUtils.js +187 -0
  111. package/dist-esm/helpers/nameUtils.js.map +1 -0
  112. package/dist-esm/helpers/operationHelpers.js +84 -0
  113. package/dist-esm/helpers/operationHelpers.js.map +1 -0
  114. package/dist-esm/helpers/pathUtils.js +9 -0
  115. package/dist-esm/helpers/pathUtils.js.map +1 -0
  116. package/dist-esm/helpers/schemaHelpers.js +21 -0
  117. package/dist-esm/helpers/schemaHelpers.js.map +1 -0
  118. package/dist-esm/helpers/shortcutMethods.js +42 -0
  119. package/dist-esm/helpers/shortcutMethods.js.map +1 -0
  120. package/dist-esm/index.js +29 -0
  121. package/dist-esm/index.js.map +1 -0
  122. package/dist-esm/interfaces.js +15 -0
  123. package/dist-esm/interfaces.js.map +1 -0
  124. package/dist-esm/metadata/buildApiExtractorConfig.js +51 -0
  125. package/dist-esm/metadata/buildApiExtractorConfig.js.map +1 -0
  126. package/dist-esm/metadata/buildESLintConfig.js +28 -0
  127. package/dist-esm/metadata/buildESLintConfig.js.map +1 -0
  128. package/dist-esm/metadata/buildLicenseFile.js +36 -0
  129. package/dist-esm/metadata/buildLicenseFile.js.map +1 -0
  130. package/dist-esm/metadata/buildPackageFile.js +276 -0
  131. package/dist-esm/metadata/buildPackageFile.js.map +1 -0
  132. package/dist-esm/metadata/buildReadmeFile.js +167 -0
  133. package/dist-esm/metadata/buildReadmeFile.js.map +1 -0
  134. package/dist-esm/metadata/buildRollupConfig.js +139 -0
  135. package/dist-esm/metadata/buildRollupConfig.js.map +1 -0
  136. package/dist-esm/metadata/buildTsConfig.js +67 -0
  137. package/dist-esm/metadata/buildTsConfig.js.map +1 -0
  138. package/dist-esm/package.json +1 -0
  139. package/dist-esm/static/paginateContent.js +211 -0
  140. package/dist-esm/static/paginateContent.js.map +1 -0
  141. package/dist-esm/static/pollingContent.js +95 -0
  142. package/dist-esm/static/pollingContent.js.map +1 -0
  143. package/dist-esm/static/serializeHelper.js +27 -0
  144. package/dist-esm/static/serializeHelper.js.map +1 -0
  145. package/dist-esm/test/buildEnvFile.js +24 -0
  146. package/dist-esm/test/buildEnvFile.js.map +1 -0
  147. package/dist-esm/test/buildKarmaConfig.js +14 -0
  148. package/dist-esm/test/buildKarmaConfig.js.map +1 -0
  149. package/dist-esm/test/buildRecordedClient.js +17 -0
  150. package/dist-esm/test/buildRecordedClient.js.map +1 -0
  151. package/dist-esm/test/buildSampleTest.js +14 -0
  152. package/dist-esm/test/buildSampleTest.js.map +1 -0
  153. package/dist-esm/test/template.js +188 -0
  154. package/dist-esm/test/template.js.map +1 -0
  155. package/package.json +46 -0
  156. package/publishPackage.js +11 -0
  157. package/rlc-common.build.log +2 -0
  158. package/src/buildClient.ts +353 -0
  159. package/src/buildClientDefinitions.ts +235 -0
  160. package/src/buildIndexFile.ts +202 -0
  161. package/src/buildIsUnexpectedHelper.ts +240 -0
  162. package/src/buildMethodShortcuts.ts +75 -0
  163. package/src/buildObjectTypes.ts +449 -0
  164. package/src/buildPaginateHelper.ts +33 -0
  165. package/src/buildParameterTypes.ts +477 -0
  166. package/src/buildPollingHelper.ts +18 -0
  167. package/src/buildResponseTypes.ts +186 -0
  168. package/src/buildSchemaType.ts +85 -0
  169. package/src/buildSerializeHelper.ts +42 -0
  170. package/src/buildTopLevelIndexFile.ts +52 -0
  171. package/src/helpers/nameConstructors.ts +93 -0
  172. package/src/helpers/nameUtils.ts +227 -0
  173. package/src/helpers/operationHelpers.ts +119 -0
  174. package/src/helpers/pathUtils.ts +9 -0
  175. package/src/helpers/schemaHelpers.ts +25 -0
  176. package/src/helpers/shortcutMethods.ts +60 -0
  177. package/src/index.ts +29 -0
  178. package/src/interfaces.ts +227 -0
  179. package/src/metadata/buildApiExtractorConfig.ts +59 -0
  180. package/src/metadata/buildESLintConfig.ts +34 -0
  181. package/src/metadata/buildLicenseFile.ts +39 -0
  182. package/src/metadata/buildPackageFile.ts +334 -0
  183. package/src/metadata/buildReadmeFile.ts +231 -0
  184. package/src/metadata/buildRollupConfig.ts +147 -0
  185. package/src/metadata/buildTsConfig.ts +79 -0
  186. package/src/static/paginateContent.ts +210 -0
  187. package/src/static/pollingContent.ts +94 -0
  188. package/src/static/serializeHelper.ts +29 -0
  189. package/src/test/buildEnvFile.ts +26 -0
  190. package/src/test/buildKarmaConfig.ts +15 -0
  191. package/src/test/buildRecordedClient.ts +18 -0
  192. package/src/test/buildSampleTest.ts +15 -0
  193. package/src/test/template.ts +191 -0
  194. package/tsconfig-cjs.json +9 -0
  195. package/tsconfig-common.json +13 -0
  196. package/tsconfig.json +13 -0
  197. package/types/buildClient.d.ts +2 -0
  198. package/types/buildClientDefinitions.d.ts +5 -0
  199. package/types/buildIndexFile.d.ts +5 -0
  200. package/types/buildIsUnexpectedHelper.d.ts +5 -0
  201. package/types/buildMethodShortcuts.d.ts +4 -0
  202. package/types/buildObjectTypes.d.ts +15 -0
  203. package/types/buildPaginateHelper.d.ts +5 -0
  204. package/types/buildParameterTypes.d.ts +13 -0
  205. package/types/buildPollingHelper.d.ts +5 -0
  206. package/types/buildResponseTypes.d.ts +5 -0
  207. package/types/buildSchemaType.d.ts +19 -0
  208. package/types/buildSerializeHelper.d.ts +5 -0
  209. package/types/buildTopLevelIndexFile.d.ts +5 -0
  210. package/types/helpers/nameConstructors.d.ts +28 -0
  211. package/types/helpers/nameUtils.d.ts +25 -0
  212. package/types/helpers/operationHelpers.d.ts +13 -0
  213. package/types/helpers/pathUtils.d.ts +1 -0
  214. package/types/helpers/schemaHelpers.d.ts +4 -0
  215. package/types/helpers/shortcutMethods.d.ts +3 -0
  216. package/types/index.d.ts +26 -0
  217. package/types/interfaces.d.ts +200 -0
  218. package/types/metadata/buildApiExtractorConfig.d.ts +5 -0
  219. package/types/metadata/buildESLintConfig.d.ts +5 -0
  220. package/types/metadata/buildLicenseFile.d.ts +5 -0
  221. package/types/metadata/buildPackageFile.d.ts +5 -0
  222. package/types/metadata/buildReadmeFile.d.ts +5 -0
  223. package/types/metadata/buildRollupConfig.d.ts +5 -0
  224. package/types/metadata/buildTsConfig.d.ts +5 -0
  225. package/types/static/paginateContent.d.ts +1 -0
  226. package/types/static/pollingContent.d.ts +1 -0
  227. package/types/static/serializeHelper.d.ts +4 -0
  228. package/types/test/buildEnvFile.d.ts +9 -0
  229. package/types/test/buildKarmaConfig.d.ts +5 -0
  230. package/types/test/buildRecordedClient.d.ts +5 -0
  231. package/types/test/buildSampleTest.d.ts +5 -0
  232. package/types/test/template.d.ts +5 -0
@@ -0,0 +1,477 @@
1
+ // Copyright (c) Microsoft Corporation.
2
+ // Licensed under the MIT License.
3
+
4
+ import {
5
+ InterfaceDeclarationStructure,
6
+ Project,
7
+ PropertySignatureStructure,
8
+ SourceFile,
9
+ StructureKind
10
+ } from "ts-morph";
11
+ import * as path from "path";
12
+ import {
13
+ ImportKind,
14
+ ObjectSchema,
15
+ ParameterMetadata,
16
+ ParameterMetadatas,
17
+ RLCModel,
18
+ Schema
19
+ } from "./interfaces.js";
20
+ import {
21
+ getParameterBaseName,
22
+ getParameterTypeName
23
+ } from "./helpers/nameConstructors.js";
24
+
25
+ export function buildParameterTypes(model: RLCModel) {
26
+ const project = new Project();
27
+ const srcPath = model.srcPath;
28
+ const filePath = path.join(srcPath, `parameters.ts`);
29
+ const parametersFile = project.createSourceFile(filePath, undefined, {
30
+ overwrite: true
31
+ });
32
+ let hasHeaders = false;
33
+
34
+ if (!model.parameters) {
35
+ return;
36
+ }
37
+ for (const requestParameter of model.parameters) {
38
+ const baseParameterName = getParameterBaseName(
39
+ requestParameter.operationGroup,
40
+ requestParameter.operationName
41
+ );
42
+ const requestCount = requestParameter?.parameters?.length ?? 0;
43
+ const topParamName = getParameterTypeName(baseParameterName);
44
+ const subParamNames: string[] = [];
45
+
46
+ // We need to loop the requests. An operation with multiple requests means that
47
+ // the operation can get different values for content-type and each value may
48
+ // have a different type associated to it.
49
+ for (let i = 0; i < requestCount; i++) {
50
+ const parameter = requestParameter.parameters[i];
51
+ const internalReferences = new Set<string>();
52
+ // In case we have more than one request to model we need to add a suffix to differentiate
53
+ const nameSuffix = i > 0 ? `${i}` : "";
54
+ const parameterInterfaceName =
55
+ requestCount > 1
56
+ ? `${baseParameterName}RequestParameters${nameSuffix}`
57
+ : topParamName;
58
+ const queryParameterDefinitions = buildQueryParameterDefinition(
59
+ parameter,
60
+ baseParameterName,
61
+ internalReferences,
62
+ i
63
+ );
64
+ const pathParameterDefinitions = buildPathParameterDefinitions(
65
+ parameter,
66
+ baseParameterName,
67
+ parametersFile,
68
+ internalReferences,
69
+ i
70
+ );
71
+
72
+ const headerParameterDefinitions = buildHeaderParameterDefinitions(
73
+ parameter,
74
+ baseParameterName,
75
+ parametersFile,
76
+ internalReferences,
77
+ i
78
+ );
79
+
80
+ const contentTypeParameterDefinition =
81
+ buildContentTypeParametersDefinition(
82
+ parameter,
83
+ baseParameterName,
84
+ internalReferences,
85
+ i
86
+ );
87
+
88
+ const bodyParameterDefinition = buildBodyParametersDefinition(
89
+ parameter,
90
+ baseParameterName,
91
+ internalReferences,
92
+ i
93
+ );
94
+
95
+ const bodyTypeAlias = buildBodyTypeAlias(parameter);
96
+ if (bodyTypeAlias) {
97
+ parametersFile.addTypeAlias(bodyTypeAlias);
98
+ }
99
+
100
+ // Add interfaces for body and query parameters
101
+ parametersFile.addInterfaces([
102
+ ...(bodyParameterDefinition ?? []),
103
+ ...(queryParameterDefinitions ?? []),
104
+ ...(pathParameterDefinitions ? [pathParameterDefinitions] : []),
105
+ ...(headerParameterDefinitions ? [headerParameterDefinitions] : []),
106
+ ...(contentTypeParameterDefinition
107
+ ? [contentTypeParameterDefinition]
108
+ : [])
109
+ ]);
110
+
111
+ // Add Operation parameters type alias which is composed of the types we generated above
112
+ // plus the common type RequestParameters
113
+ parametersFile.addTypeAlias({
114
+ name: parameterInterfaceName,
115
+ isExported: true,
116
+ type: [...internalReferences, "RequestParameters"].join(" & ")
117
+ });
118
+
119
+ subParamNames.push(parameterInterfaceName);
120
+
121
+ if (headerParameterDefinitions !== undefined) {
122
+ hasHeaders = true;
123
+ }
124
+ }
125
+ // Add Operation parameters type alias which is composed of the types we generated above
126
+ // plus the common type RequestParameters
127
+ if (requestCount > 1) {
128
+ parametersFile.addTypeAlias({
129
+ name: topParamName,
130
+ isExported: true,
131
+ type: [...subParamNames].join(" | ")
132
+ });
133
+ }
134
+ }
135
+
136
+ if (hasHeaders) {
137
+ parametersFile.addImportDeclarations([
138
+ {
139
+ namedImports: ["RawHttpHeadersInput"],
140
+ moduleSpecifier: "@azure/core-rest-pipeline"
141
+ }
142
+ ]);
143
+ }
144
+ parametersFile.addImportDeclarations([
145
+ {
146
+ namedImports: ["RequestParameters"],
147
+ moduleSpecifier: "@azure-rest/core-client"
148
+ }
149
+ ]);
150
+ if (model.importSet?.has(ImportKind.ParameterInput)) {
151
+ parametersFile.addImportDeclarations([
152
+ {
153
+ namedImports: [
154
+ ...Array.from(model.importSet?.get(ImportKind.ParameterInput) || [])
155
+ ],
156
+ moduleSpecifier: "./models"
157
+ }
158
+ ]);
159
+ }
160
+ return { path: filePath, content: parametersFile.getFullText() };
161
+ }
162
+
163
+ function buildQueryParameterDefinition(
164
+ parameters: ParameterMetadatas,
165
+ baseName: string,
166
+ internalReferences: Set<string>,
167
+ requestIndex: number
168
+ ): InterfaceDeclarationStructure[] | undefined {
169
+ const queryParameters = (parameters?.parameters || []).filter(
170
+ (p) => p.type === "query"
171
+ );
172
+
173
+ if (!queryParameters.length) {
174
+ return undefined;
175
+ }
176
+
177
+ const nameSuffix = requestIndex > 0 ? `${requestIndex}` : "";
178
+ const queryParameterInterfaceName = `${baseName}QueryParam${nameSuffix}`;
179
+ const queryParameterPropertiesName = `${baseName}QueryParamProperties`;
180
+
181
+ // Get the property signature for each query parameter
182
+ const propertiesDefinition = queryParameters.map((qp) =>
183
+ getPropertyFromSchema(qp.param)
184
+ );
185
+
186
+ const hasRequiredParameters = propertiesDefinition.some(
187
+ (p) => !p.hasQuestionToken
188
+ );
189
+
190
+ const propertiesInterface: InterfaceDeclarationStructure = {
191
+ kind: StructureKind.Interface,
192
+ isExported: true,
193
+ name: queryParameterPropertiesName,
194
+ properties: propertiesDefinition
195
+ };
196
+
197
+ const parameterInterface: InterfaceDeclarationStructure = {
198
+ kind: StructureKind.Interface,
199
+ isExported: true,
200
+ name: queryParameterInterfaceName,
201
+ properties: [
202
+ {
203
+ name: "queryParameters",
204
+ type: queryParameterPropertiesName,
205
+ // Mark as optional if there are no required parameters
206
+ hasQuestionToken: !hasRequiredParameters
207
+ }
208
+ ]
209
+ };
210
+
211
+ // Mark the queryParameter interface for importing
212
+ internalReferences.add(queryParameterInterfaceName);
213
+
214
+ return [propertiesInterface, parameterInterface];
215
+ }
216
+
217
+ function getPropertyFromSchema(schema: Schema): PropertySignatureStructure {
218
+ const description = schema.description;
219
+ return {
220
+ name: schema.name,
221
+ ...(description && { docs: [{ description }] }),
222
+ type: schema.type,
223
+ hasQuestionToken: !schema.required,
224
+ kind: StructureKind.PropertySignature
225
+ };
226
+ }
227
+
228
+ function buildPathParameterDefinitions(
229
+ parameters: ParameterMetadatas,
230
+ baseName: string,
231
+ parametersFile: SourceFile,
232
+ internalReferences: Set<string>,
233
+ requestIndex: number
234
+ ): InterfaceDeclarationStructure | undefined {
235
+ const pathParameters = (parameters.parameters || []).filter(
236
+ (p) => p.type === "path"
237
+ );
238
+ if (!pathParameters.length) {
239
+ return undefined;
240
+ }
241
+
242
+ const nameSuffix = requestIndex > 0 ? `${requestIndex}` : "";
243
+ const pathParameterInterfaceName = `${baseName}PathParam${nameSuffix}`;
244
+
245
+ const pathInterface = getPathInterfaceDefinition(pathParameters, baseName);
246
+
247
+ if (pathInterface) {
248
+ parametersFile.addInterface(pathInterface);
249
+ }
250
+
251
+ internalReferences.add(pathParameterInterfaceName);
252
+
253
+ return {
254
+ isExported: true,
255
+ kind: StructureKind.Interface,
256
+ name: pathParameterInterfaceName,
257
+ properties: [
258
+ {
259
+ name: "pathParameters",
260
+ type: `${baseName}PathParameters`,
261
+ kind: StructureKind.PropertySignature
262
+ }
263
+ ]
264
+ };
265
+ }
266
+
267
+ function getPathInterfaceDefinition(
268
+ pathParameters: ParameterMetadata[],
269
+ baseName: string
270
+ ): undefined | InterfaceDeclarationStructure {
271
+ const pathInterfaceName = `${baseName}PathParameters`;
272
+ return {
273
+ kind: StructureKind.Interface,
274
+ isExported: true,
275
+ name: pathInterfaceName,
276
+ properties: pathParameters.map((p: ParameterMetadata) =>
277
+ getPropertyFromSchema(p.param)
278
+ )
279
+ };
280
+ }
281
+
282
+ function buildHeaderParameterDefinitions(
283
+ parameters: ParameterMetadatas,
284
+ baseName: string,
285
+ parametersFile: SourceFile,
286
+ internalReferences: Set<string>,
287
+ requestIndex: number
288
+ ): InterfaceDeclarationStructure | undefined {
289
+ const headerParameters = (parameters.parameters || []).filter(
290
+ (p) => p.type === "header" && p.name !== "contentType"
291
+ );
292
+ if (!headerParameters.length) {
293
+ return undefined;
294
+ }
295
+
296
+ const nameSuffix = requestIndex > 0 ? `${requestIndex}` : "";
297
+ const headerParameterInterfaceName = `${baseName}HeaderParam${nameSuffix}`;
298
+
299
+ const headersInterface = getRequestHeaderInterfaceDefinition(
300
+ headerParameters,
301
+ baseName
302
+ );
303
+
304
+ let isOptional = true;
305
+ if (headersInterface) {
306
+ parametersFile.addInterface(headersInterface);
307
+ isOptional = !(headersInterface.properties || []).some(
308
+ (prop) => prop.hasQuestionToken === false
309
+ );
310
+ }
311
+
312
+ internalReferences.add(headerParameterInterfaceName);
313
+
314
+ return {
315
+ isExported: true,
316
+ kind: StructureKind.Interface,
317
+ name: headerParameterInterfaceName,
318
+ properties: [
319
+ {
320
+ name: "headers",
321
+ type: `RawHttpHeadersInput & ${baseName}Headers`,
322
+ kind: StructureKind.PropertySignature,
323
+ hasQuestionToken: isOptional
324
+ }
325
+ ]
326
+ };
327
+ }
328
+
329
+ function getRequestHeaderInterfaceDefinition(
330
+ headerParameters: ParameterMetadata[],
331
+ baseName: string
332
+ ): undefined | InterfaceDeclarationStructure {
333
+ const headersInterfaceName = `${baseName}Headers`;
334
+ return {
335
+ kind: StructureKind.Interface,
336
+ isExported: true,
337
+ name: headersInterfaceName,
338
+ properties: headerParameters.map((h: ParameterMetadata) =>
339
+ getPropertyFromSchema(h.param)
340
+ )
341
+ };
342
+ }
343
+
344
+ function buildContentTypeParametersDefinition(
345
+ parameters: ParameterMetadatas,
346
+ baseName: string,
347
+ internalReferences: Set<string>,
348
+ requestIndex: number
349
+ ): InterfaceDeclarationStructure | undefined {
350
+ const mediaTypeParameters = (parameters.parameters || []).filter(
351
+ (p) => p.type === "header" && p.name === "contentType"
352
+ );
353
+ if (!mediaTypeParameters.length) {
354
+ return undefined;
355
+ }
356
+
357
+ const nameSuffix = requestIndex > 0 ? `${requestIndex}` : "";
358
+ const mediaTypesParameterInterfaceName = `${baseName}MediaTypesParam${nameSuffix}`;
359
+
360
+ // Mark the queryParameter interface for importing
361
+ internalReferences.add(mediaTypesParameterInterfaceName);
362
+ const mediaParam = mediaTypeParameters[0].param;
363
+
364
+ return {
365
+ isExported: true,
366
+ kind: StructureKind.Interface,
367
+ name: mediaTypesParameterInterfaceName,
368
+ properties: [getPropertyFromSchema(mediaParam)]
369
+ };
370
+ }
371
+
372
+ function buildBodyParametersDefinition(
373
+ parameters: ParameterMetadatas,
374
+ baseName: string,
375
+ internalReferences: Set<string>,
376
+ requestIndex: number
377
+ ): InterfaceDeclarationStructure[] {
378
+ const bodyParameters = parameters.body;
379
+ if (
380
+ !bodyParameters ||
381
+ !bodyParameters?.body ||
382
+ !bodyParameters?.body.length
383
+ ) {
384
+ return [];
385
+ }
386
+
387
+ const nameSuffix = requestIndex > 0 ? `${requestIndex}` : "";
388
+ const bodyParameterInterfaceName = `${baseName}BodyParam${nameSuffix}`;
389
+ internalReferences.add(bodyParameterInterfaceName);
390
+
391
+ // In case of formData we'd get multiple properties in body marked as partialBody
392
+ if (bodyParameters.isPartialBody) {
393
+ let allOptionalParts = true;
394
+ const propertiesDefinitions: PropertySignatureStructure[] = [];
395
+ for (const param of bodyParameters.body) {
396
+ if (param.required) {
397
+ allOptionalParts = false;
398
+ }
399
+
400
+ propertiesDefinitions.push(getPropertyFromSchema(param));
401
+ }
402
+
403
+ const formBodyName = `${baseName}FormBody`;
404
+ const formBodyInterface: InterfaceDeclarationStructure = {
405
+ isExported: true,
406
+ kind: StructureKind.Interface,
407
+ name: formBodyName,
408
+ properties: propertiesDefinitions
409
+ };
410
+
411
+ return [
412
+ {
413
+ isExported: true,
414
+ kind: StructureKind.Interface,
415
+ name: bodyParameterInterfaceName,
416
+ properties: [
417
+ {
418
+ name: "body",
419
+ type: formBodyName,
420
+ hasQuestionToken: allOptionalParts
421
+ }
422
+ ]
423
+ },
424
+ formBodyInterface
425
+ ];
426
+ } else {
427
+ const bodySignature = getPropertyFromSchema(bodyParameters.body[0]);
428
+
429
+ return [
430
+ {
431
+ isExported: true,
432
+ kind: StructureKind.Interface,
433
+ name: bodyParameterInterfaceName,
434
+ properties: [
435
+ {
436
+ docs: bodySignature.docs,
437
+ name: "body",
438
+ type: bodySignature.type,
439
+ hasQuestionToken: bodySignature.hasQuestionToken
440
+ }
441
+ ]
442
+ }
443
+ ];
444
+ }
445
+ }
446
+
447
+ export function buildBodyTypeAlias(parameters: ParameterMetadatas) {
448
+ const bodyParameters = parameters.body;
449
+ if (
450
+ !bodyParameters ||
451
+ !bodyParameters?.body ||
452
+ !bodyParameters?.body.length
453
+ ) {
454
+ return undefined;
455
+ }
456
+ const schema = bodyParameters.body[0] as ObjectSchema;
457
+ const headerParameters = (parameters.parameters || []).filter(
458
+ (p) => p.type === "header" && p.name === "contentType"
459
+ );
460
+ if (!headerParameters.length || headerParameters.length > 1) {
461
+ return undefined;
462
+ }
463
+
464
+ const contentType = headerParameters[0].param.type;
465
+ const description = `${schema.description}`;
466
+ const typeName = `${schema.typeName}ResourceMergeAndPatch`;
467
+ if (contentType.includes("application/merge-patch+json")) {
468
+ const type = `Partial<${schema.typeName}>`;
469
+ return {
470
+ // kind: StructureKind.TypeAlias,
471
+ ...(description && { docs: [{ description }] }),
472
+ name: `${typeName}`,
473
+ type,
474
+ isExported: true
475
+ };
476
+ }
477
+ }
@@ -0,0 +1,18 @@
1
+ import { RLCModel } from "./interfaces.js";
2
+ import * as path from "path";
3
+ // @ts-ignore: to fix the handlebars issue
4
+ import hbs from "handlebars";
5
+ import { hasPollingOperations } from "./helpers/operationHelpers.js";
6
+ import { pollingContent } from "./static/pollingContent.js";
7
+
8
+ export function buildPollingHelper(model: RLCModel) {
9
+ if (!hasPollingOperations(model)) {
10
+ return;
11
+ }
12
+ const readmeFileContents = hbs.compile(pollingContent, { noEscape: true });
13
+ const { srcPath } = model;
14
+ return {
15
+ path: path.join(srcPath, "pollingHelper.ts"),
16
+ content: readmeFileContents({})
17
+ };
18
+ }
@@ -0,0 +1,186 @@
1
+ // Copyright (c) Microsoft Corporation.
2
+ // Licensed under the MIT License.
3
+
4
+ import {
5
+ InterfaceDeclarationStructure,
6
+ OptionalKind,
7
+ Project,
8
+ PropertySignatureStructure,
9
+ StructureKind
10
+ } from "ts-morph";
11
+ import {
12
+ ImportKind,
13
+ ResponseHeaderSchema,
14
+ ResponseMetadata,
15
+ RLCModel
16
+ } from "./interfaces.js";
17
+ import * as path from "path";
18
+ import {
19
+ getResponseBaseName,
20
+ getResponseTypeName
21
+ } from "./helpers/nameConstructors.js";
22
+
23
+ let hasErrorResponse = false;
24
+ export function buildResponseTypes(model: RLCModel) {
25
+ const project = new Project();
26
+ const srcPath = model.srcPath;
27
+ const filePath = path.join(srcPath, `responses.ts`);
28
+ hasErrorResponse = false;
29
+ const responsesFile = project.createSourceFile(filePath, undefined, {
30
+ overwrite: true
31
+ });
32
+ // Set used to track down which models need to be imported
33
+ // Track if we need to import RawHttpHeaders
34
+ let hasHeaders = false;
35
+ if (!model.responses) {
36
+ return;
37
+ }
38
+ for (const operationResponse of model.responses) {
39
+ for (const response of operationResponse.responses) {
40
+ // Building the response type base name
41
+ const baseResponseName = getResponseBaseName(
42
+ operationResponse.operationGroup,
43
+ operationResponse.operationName,
44
+ response.statusCode
45
+ );
46
+
47
+ // Build the response header
48
+ const headersInterface: InterfaceDeclarationStructure | undefined =
49
+ getResponseHeaderInterfaceDefinition(response, baseResponseName);
50
+ if (headersInterface) {
51
+ hasHeaders = true;
52
+ responsesFile.addInterface(headersInterface);
53
+ }
54
+
55
+ // Get the information to build the Response Interface
56
+ const responseTypeName = getResponseTypeName(baseResponseName);
57
+ const responseProperties = getResponseInterfaceProperties(
58
+ response,
59
+ headersInterface?.name
60
+ );
61
+
62
+ const responseInterfaceDefinition: OptionalKind<InterfaceDeclarationStructure> =
63
+ {
64
+ name: responseTypeName,
65
+ properties: responseProperties,
66
+ isExported: true,
67
+ extends: ["HttpResponse"]
68
+ };
69
+
70
+ // Only add a description if one was provided in the Swagger
71
+ // otherwise skip to avoid having empty TSDoc lines
72
+ if (response.description) {
73
+ responseInterfaceDefinition.docs = [
74
+ { description: response.description }
75
+ ];
76
+ }
77
+
78
+ // Add the response interface to the responses file
79
+ responsesFile.addInterface(responseInterfaceDefinition);
80
+ }
81
+ }
82
+
83
+ if (hasHeaders) {
84
+ responsesFile.addImportDeclarations([
85
+ {
86
+ namedImports: ["RawHttpHeaders"],
87
+ moduleSpecifier: "@azure/core-rest-pipeline"
88
+ }
89
+ ]);
90
+ }
91
+ const namedImports = ["HttpResponse"];
92
+ if (hasErrorResponse) {
93
+ namedImports.push("ErrorResponse");
94
+ }
95
+ responsesFile.addImportDeclarations([
96
+ {
97
+ namedImports,
98
+ moduleSpecifier: "@azure-rest/core-client"
99
+ }
100
+ ]);
101
+
102
+ if (model.importSet?.has(ImportKind.ResponseOutput)) {
103
+ const modelNamedImports = Array.from(
104
+ model.importSet.get(ImportKind.ResponseOutput) || []
105
+ ).filter((modelName) => {
106
+ return !(modelName === "ErrorResponseOutput" && hasErrorResponse);
107
+ });
108
+ responsesFile.addImportDeclarations([
109
+ {
110
+ namedImports: modelNamedImports,
111
+ moduleSpecifier: "./outputModels"
112
+ }
113
+ ]);
114
+ }
115
+ return { path: filePath, content: responsesFile.getFullText() };
116
+ }
117
+
118
+ function getResponseHeaderInterfaceDefinition(
119
+ response: ResponseMetadata,
120
+ baseName: string
121
+ ): undefined | InterfaceDeclarationStructure {
122
+ // Check if there are any required headers
123
+ if (!response.headers) {
124
+ return;
125
+ }
126
+ const headersInterfaceName = `${baseName}Headers`;
127
+ return {
128
+ kind: StructureKind.Interface,
129
+ isExported: true,
130
+ name: headersInterfaceName,
131
+ properties: response?.headers.map((h: ResponseHeaderSchema) => {
132
+ const description = h.description;
133
+ return {
134
+ name: h.name,
135
+ ...(description && { docs: [{ description }] }),
136
+ type: h.type,
137
+ hasQuestionToken: !h.required
138
+ };
139
+ })
140
+ };
141
+ }
142
+
143
+ /**
144
+ * Gets the properties that need to be part of the response interface
145
+ */
146
+ function getResponseInterfaceProperties(
147
+ response: ResponseMetadata,
148
+ headersInterfaceName?: string
149
+ ) {
150
+ const statusCode = response.statusCode;
151
+ const responseProperties: PropertySignatureStructure[] = [
152
+ {
153
+ name: "status",
154
+ type: statusCode === "default" ? `string` : `"${statusCode}"`,
155
+ kind: StructureKind.PropertySignature
156
+ }
157
+ ];
158
+
159
+ if (response.body) {
160
+ const description = response.body.description;
161
+ let type = response.body.type;
162
+ if (
163
+ response.body.type === "ErrorResponseOutput" &&
164
+ response.body.fromCore
165
+ ) {
166
+ type = "ErrorResponse";
167
+ hasErrorResponse = true;
168
+ }
169
+ responseProperties.push({
170
+ name: "body",
171
+ type,
172
+ kind: StructureKind.PropertySignature,
173
+ ...(description && { docs: [{ description }] })
174
+ });
175
+ }
176
+
177
+ if (headersInterfaceName) {
178
+ responseProperties.push({
179
+ name: "headers",
180
+ type: `RawHttpHeaders & ${headersInterfaceName}`,
181
+ kind: StructureKind.PropertySignature
182
+ });
183
+ }
184
+
185
+ return responseProperties;
186
+ }