@goast/kotlin 0.5.14 → 0.6.0-beta.2

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 (130) hide show
  1. package/esm/src/ast/references/jackson.d.ts +8 -0
  2. package/esm/src/ast/references/jackson.d.ts.map +1 -1
  3. package/esm/src/ast/references/jackson.js +8 -0
  4. package/esm/src/generators/file-generator.d.ts +21 -1
  5. package/esm/src/generators/file-generator.d.ts.map +1 -1
  6. package/esm/src/generators/file-generator.js +41 -2
  7. package/esm/src/generators/models/args.d.ts +5 -0
  8. package/esm/src/generators/models/args.d.ts.map +1 -1
  9. package/esm/src/generators/models/model-generator.d.ts +23 -0
  10. package/esm/src/generators/models/model-generator.d.ts.map +1 -1
  11. package/esm/src/generators/models/model-generator.js +117 -9
  12. package/esm/src/generators/services/okhttp3-clients/okhttp3-client-generator.d.ts +9 -0
  13. package/esm/src/generators/services/okhttp3-clients/okhttp3-client-generator.d.ts.map +1 -1
  14. package/esm/src/generators/services/okhttp3-clients/okhttp3-client-generator.js +14 -3
  15. package/esm/src/generators/services/okhttp3-clients/okhttp3-clients-generator.d.ts.map +1 -1
  16. package/esm/src/generators/services/okhttp3-clients/okhttp3-clients-generator.js +3 -1
  17. package/esm/src/generators/services/spring-controllers/spring-controller-generator.d.ts.map +1 -1
  18. package/esm/src/generators/services/spring-controllers/spring-controller-generator.js +11 -3
  19. package/esm/src/generators/services/spring-reactive-web-clients/args.d.ts +3 -0
  20. package/esm/src/generators/services/spring-reactive-web-clients/args.d.ts.map +1 -1
  21. package/esm/src/generators/services/spring-reactive-web-clients/spring-reactive-web-client-generator.d.ts +7 -0
  22. package/esm/src/generators/services/spring-reactive-web-clients/spring-reactive-web-client-generator.d.ts.map +1 -1
  23. package/esm/src/generators/services/spring-reactive-web-clients/spring-reactive-web-client-generator.js +18 -6
  24. package/esm/src/import-collection.d.ts.map +1 -1
  25. package/esm/src/import-collection.js +2 -2
  26. package/package.json +2 -2
  27. package/script/src/ast/references/jackson.d.ts +8 -0
  28. package/script/src/ast/references/jackson.d.ts.map +1 -1
  29. package/script/src/ast/references/jackson.js +9 -1
  30. package/script/src/generators/file-generator.d.ts +21 -1
  31. package/script/src/generators/file-generator.d.ts.map +1 -1
  32. package/script/src/generators/file-generator.js +41 -2
  33. package/script/src/generators/models/args.d.ts +5 -0
  34. package/script/src/generators/models/args.d.ts.map +1 -1
  35. package/script/src/generators/models/model-generator.d.ts +23 -0
  36. package/script/src/generators/models/model-generator.d.ts.map +1 -1
  37. package/script/src/generators/models/model-generator.js +117 -9
  38. package/script/src/generators/services/okhttp3-clients/okhttp3-client-generator.d.ts +9 -0
  39. package/script/src/generators/services/okhttp3-clients/okhttp3-client-generator.d.ts.map +1 -1
  40. package/script/src/generators/services/okhttp3-clients/okhttp3-client-generator.js +14 -3
  41. package/script/src/generators/services/okhttp3-clients/okhttp3-clients-generator.d.ts.map +1 -1
  42. package/script/src/generators/services/okhttp3-clients/okhttp3-clients-generator.js +3 -1
  43. package/script/src/generators/services/spring-controllers/spring-controller-generator.d.ts.map +1 -1
  44. package/script/src/generators/services/spring-controllers/spring-controller-generator.js +11 -3
  45. package/script/src/generators/services/spring-reactive-web-clients/args.d.ts +3 -0
  46. package/script/src/generators/services/spring-reactive-web-clients/args.d.ts.map +1 -1
  47. package/script/src/generators/services/spring-reactive-web-clients/spring-reactive-web-client-generator.d.ts +7 -0
  48. package/script/src/generators/services/spring-reactive-web-clients/spring-reactive-web-client-generator.d.ts.map +1 -1
  49. package/script/src/generators/services/spring-reactive-web-clients/spring-reactive-web-client-generator.js +18 -6
  50. package/script/src/import-collection.d.ts.map +1 -1
  51. package/script/src/import-collection.js +1 -1
  52. package/src/mod.ts +0 -8
  53. package/src/src/assets.ts +0 -9
  54. package/src/src/ast/_index.ts +0 -66
  55. package/src/src/ast/common.ts +0 -1
  56. package/src/src/ast/index.ts +0 -1
  57. package/src/src/ast/node.ts +0 -10
  58. package/src/src/ast/nodes/annotation.ts +0 -79
  59. package/src/src/ast/nodes/argument.ts +0 -62
  60. package/src/src/ast/nodes/call.ts +0 -75
  61. package/src/src/ast/nodes/class.ts +0 -178
  62. package/src/src/ast/nodes/collection-literal.ts +0 -49
  63. package/src/src/ast/nodes/constructor.ts +0 -126
  64. package/src/src/ast/nodes/doc-tag.ts +0 -138
  65. package/src/src/ast/nodes/doc.ts +0 -111
  66. package/src/src/ast/nodes/enum-value.ts +0 -100
  67. package/src/src/ast/nodes/enum.ts +0 -163
  68. package/src/src/ast/nodes/function.ts +0 -178
  69. package/src/src/ast/nodes/generic-parameter.ts +0 -54
  70. package/src/src/ast/nodes/init-block.ts +0 -38
  71. package/src/src/ast/nodes/interface.ts +0 -133
  72. package/src/src/ast/nodes/lambda-type.ts +0 -73
  73. package/src/src/ast/nodes/lambda.ts +0 -74
  74. package/src/src/ast/nodes/object.ts +0 -102
  75. package/src/src/ast/nodes/parameter.ts +0 -118
  76. package/src/src/ast/nodes/property.ts +0 -225
  77. package/src/src/ast/nodes/reference.ts +0 -178
  78. package/src/src/ast/nodes/string.ts +0 -114
  79. package/src/src/ast/nodes/types.ts +0 -23
  80. package/src/src/ast/references/index.ts +0 -10
  81. package/src/src/ast/references/jackson.ts +0 -59
  82. package/src/src/ast/references/jakarta.ts +0 -14
  83. package/src/src/ast/references/java.ts +0 -27
  84. package/src/src/ast/references/kotlin.ts +0 -41
  85. package/src/src/ast/references/kotlinx.ts +0 -14
  86. package/src/src/ast/references/okhttp3.ts +0 -5
  87. package/src/src/ast/references/reactor.ts +0 -5
  88. package/src/src/ast/references/spring-reactive.ts +0 -37
  89. package/src/src/ast/references/spring.ts +0 -86
  90. package/src/src/ast/references/swagger.ts +0 -23
  91. package/src/src/ast/utils/get-kotlin-builder-options.ts +0 -19
  92. package/src/src/ast/utils/to-kt-node.ts +0 -31
  93. package/src/src/ast/utils/write-kt-annotations.ts +0 -15
  94. package/src/src/ast/utils/write-kt-arguments.ts +0 -45
  95. package/src/src/ast/utils/write-kt-enum-values.ts +0 -27
  96. package/src/src/ast/utils/write-kt-generic-parameters.ts +0 -12
  97. package/src/src/ast/utils/write-kt-members.ts +0 -25
  98. package/src/src/ast/utils/write-kt-node.ts +0 -37
  99. package/src/src/ast/utils/write-kt-parameters.ts +0 -25
  100. package/src/src/common-results.ts +0 -4
  101. package/src/src/config.ts +0 -61
  102. package/src/src/file-builder.ts +0 -112
  103. package/src/src/generators/file-generator.ts +0 -29
  104. package/src/src/generators/index.ts +0 -5
  105. package/src/src/generators/models/args.ts +0 -136
  106. package/src/src/generators/models/index.ts +0 -4
  107. package/src/src/generators/models/model-generator.ts +0 -736
  108. package/src/src/generators/models/models-generator.ts +0 -65
  109. package/src/src/generators/models/models.ts +0 -95
  110. package/src/src/generators/services/okhttp3-clients/args.ts +0 -90
  111. package/src/src/generators/services/okhttp3-clients/index.ts +0 -4
  112. package/src/src/generators/services/okhttp3-clients/models.ts +0 -73
  113. package/src/src/generators/services/okhttp3-clients/okhttp3-client-generator.ts +0 -627
  114. package/src/src/generators/services/okhttp3-clients/okhttp3-clients-generator.ts +0 -188
  115. package/src/src/generators/services/okhttp3-clients/refs.ts +0 -59
  116. package/src/src/generators/services/spring-controllers/args.ts +0 -95
  117. package/src/src/generators/services/spring-controllers/index.ts +0 -4
  118. package/src/src/generators/services/spring-controllers/models.ts +0 -76
  119. package/src/src/generators/services/spring-controllers/refs.ts +0 -17
  120. package/src/src/generators/services/spring-controllers/spring-controller-generator.ts +0 -1122
  121. package/src/src/generators/services/spring-controllers/spring-controllers-generator.ts +0 -140
  122. package/src/src/generators/services/spring-reactive-web-clients/args.ts +0 -112
  123. package/src/src/generators/services/spring-reactive-web-clients/index.ts +0 -4
  124. package/src/src/generators/services/spring-reactive-web-clients/models.ts +0 -78
  125. package/src/src/generators/services/spring-reactive-web-clients/refs.ts +0 -11
  126. package/src/src/generators/services/spring-reactive-web-clients/spring-reactive-web-client-generator.ts +0 -641
  127. package/src/src/generators/services/spring-reactive-web-clients/spring-reactive-web-clients-generator.ts +0 -125
  128. package/src/src/import-collection.ts +0 -98
  129. package/src/src/types.ts +0 -3
  130. package/src/src/utils.ts +0 -55
@@ -1,641 +0,0 @@
1
- import {
2
- type ApiParameter,
3
- type ApiSchema,
4
- type AppendValueGroup,
5
- appendValueGroup,
6
- type BasicAppendValue,
7
- builderTemplate as s,
8
- createOverwriteProxy,
9
- getSourceDisplayName,
10
- type MaybePromise,
11
- notNullish,
12
- resolveAnyOfAndAllOf,
13
- SourceBuilder,
14
- toCasing,
15
- } from '@goast/core';
16
-
17
- import { kt } from '../../../ast/index.js';
18
- import type { KtValue } from '../../../ast/nodes/types.js';
19
- import { KotlinFileBuilder } from '../../../file-builder.js';
20
- import type { ApiParameterWithMultipartInfo } from '../../../types.js';
21
- import { getArrayItemStringEnumSchema, getSourceDocLine, getStringEnumSchema, modifyString } from '../../../utils.js';
22
- import { KotlinFileGenerator } from '../../file-generator.js';
23
- import type { DefaultKotlinSpringReactiveWebClientGeneratorArgs as Args } from './index.js';
24
- import type {
25
- KotlinSpringReactiveWebClientGeneratorContext,
26
- KotlinSpringReactiveWebClientGeneratorOutput,
27
- } from './models.js';
28
-
29
- type Context = KotlinSpringReactiveWebClientGeneratorContext;
30
- type Output = KotlinSpringReactiveWebClientGeneratorOutput;
31
- type Builder = KotlinFileBuilder;
32
-
33
- export interface KotlinSpringReactiveWebClientGenerator<TOutput extends Output = Output> {
34
- generate(ctx: Context): MaybePromise<TOutput>;
35
- }
36
-
37
- export class DefaultKotlinSpringReactiveWebClientGenerator extends KotlinFileGenerator<Context, Output>
38
- implements KotlinSpringReactiveWebClientGenerator {
39
- public generate(ctx: Context): MaybePromise<Output> {
40
- const typeName = this.getRequestsObjectName(ctx, {});
41
- const packageName = this.getPackageName(ctx, {});
42
- const filePath = this.getFilePath(ctx, { packageName });
43
-
44
- console.log(`Generating client for service ${ctx.service.name} to ${filePath}...`);
45
- ctx.service.endpoints.forEach((endpoint) => {
46
- console.log(
47
- ` ${getSourceDisplayName(ctx.data, endpoint)} [${toCasing(endpoint.name, ctx.config.functionNameCasing)}]`,
48
- );
49
- });
50
-
51
- const builder = new KotlinFileBuilder(packageName, ctx.config);
52
- builder.append(this.getClientFileContent(ctx, {}));
53
- builder.writeToFile(filePath);
54
-
55
- return { typeName, packageName };
56
- }
57
-
58
- // deno-lint-ignore no-unused-vars
59
- protected getClientFileContent(ctx: Context, args: Args.GetClientFileContent): AppendValueGroup<Builder> {
60
- return appendValueGroup([this.getRequestsObject(ctx, {})], '\n\n');
61
- }
62
-
63
- // deno-lint-ignore no-unused-vars
64
- protected getRequestsObject(ctx: Context, args: Args.GetRequestsObject): kt.Object<Builder> {
65
- return kt.object({
66
- name: this.getRequestsObjectName(ctx, {}),
67
- members: ctx.service.endpoints.flatMap((endpoint) =>
68
- this.getEndpointMembers(ctx, { endpoint, parameters: this.getAllParameters(ctx, { endpoint }) })
69
- ),
70
- });
71
- }
72
-
73
- protected getEndpointMembers(ctx: Context, args: Args.GetEndpointMembers): kt.ObjectMember<Builder>[] {
74
- const { endpoint, parameters } = args;
75
- const responseSchema = this.getResponseSchema(ctx, { endpoint });
76
-
77
- return [
78
- this.getEndpointFunction(ctx, { endpoint, parameters, responseSchema }),
79
- this.getEndpointFunctionWithHandler(ctx, { endpoint, parameters, responseSchema }),
80
- this.getEndpointUriFunction(ctx, { endpoint, parameters }),
81
- this.getEndpointRequestFunction(ctx, { endpoint, parameters, responseSchema }),
82
- ];
83
- }
84
-
85
- protected getEndpointFunctionName(ctx: Context, args: Args.GetEndpointFunctionName): string {
86
- const { endpoint } = args;
87
- return toCasing(endpoint.name, ctx.config.functionNameCasing);
88
- }
89
-
90
- protected getEndpointFunction(ctx: Context, args: Args.GetEndpointFunction): kt.Function<Builder> {
91
- const { endpoint, parameters, responseSchema } = args;
92
- const functionName = this.getEndpointFunctionName(ctx, { endpoint });
93
-
94
- return kt.function(functionName, {
95
- doc: kt.doc(this.getEndpointDocDescription(ctx, { endpoint })),
96
- suspend: true,
97
- receiverType: kt.refs.springReactive.webClient(),
98
- parameters: parameters.map((parameter) =>
99
- kt.parameter(
100
- toCasing(parameter.name, ctx.config.parameterNameCasing),
101
- this.getParameterType(ctx, { endpoint, parameter }),
102
- { default: this.getParameterDefaultValue(ctx, { endpoint, parameter }) },
103
- )
104
- ),
105
- returnType: this.getTypeUsage(ctx, { schema: responseSchema, fallback: kt.refs.unit() }),
106
- body: this.getEndpointFunctionBody(ctx, { endpoint, parameters, responseSchema }),
107
- });
108
- }
109
-
110
- protected getEndpointFunctionBody(ctx: Context, args: Args.GetEndpointFunctionBody): AppendValueGroup<Builder> {
111
- const { endpoint, parameters, responseSchema } = args;
112
- const result = appendValueGroup<Builder>([], '\n');
113
-
114
- const requestFunctionName = this.getEndpointRequestFunctionName(ctx, { endpoint });
115
- const parameterNames = parameters.map((p) => toCasing(p.name, ctx.config.parameterNameCasing));
116
- const call = kt.call([
117
- 'this',
118
- kt.call(requestFunctionName, parameterNames),
119
- kt.call('retrieve', []),
120
- responseSchema
121
- ? kt.call(
122
- kt.refs.springReactive.awaitBody([
123
- this.getTypeUsage(ctx, { schema: responseSchema, fallback: kt.refs.unit() }),
124
- ]),
125
- [],
126
- )
127
- : kt.call(kt.refs.springReactive.awaitBodilessEntity(), []),
128
- ]);
129
-
130
- if (responseSchema) {
131
- result.values.push(s`return ${call}`);
132
- } else {
133
- result.values.push(call);
134
- }
135
-
136
- return result;
137
- }
138
-
139
- protected getEndpointFunctionWithHandler(
140
- ctx: Context,
141
- args: Args.GetEndpointFunctionWithHandler,
142
- ): kt.Function<Builder> {
143
- const { endpoint, parameters, responseSchema } = args;
144
- const functionName = this.getEndpointFunctionName(ctx, { endpoint });
145
-
146
- return kt.function(functionName, {
147
- doc: kt.doc(this.getEndpointDocDescription(ctx, { endpoint })),
148
- suspend: true,
149
- // Spring 7's `WebClient.awaitExchange` is `<V : Any>`, so the `<T>` overloads need an `Any` bound to infer.
150
- generics: [
151
- kt.genericParameter('T', ctx.config.springBootVersion === 4 ? { constraint: kt.refs.any() } : undefined),
152
- ],
153
- receiverType: kt.refs.springReactive.webClient(),
154
- parameters: [
155
- ...parameters.map((parameter) =>
156
- kt.parameter(
157
- toCasing(parameter.name, ctx.config.parameterNameCasing),
158
- this.getParameterType(ctx, { endpoint, parameter }),
159
- { default: this.getParameterDefaultValue(ctx, { endpoint, parameter }) },
160
- )
161
- ),
162
- kt.parameter(
163
- 'responseHandler',
164
- kt.lambdaType([kt.refs.springReactive.clientResponse()], 'T', { suspend: true }),
165
- ),
166
- ],
167
- returnType: 'T',
168
- body: this.getEndpointFunctionWithHandlerBody(ctx, { endpoint, parameters, responseSchema }),
169
- });
170
- }
171
-
172
- protected getEndpointFunctionWithHandlerBody(
173
- ctx: Context,
174
- args: Args.GetEndpointFunctionWithHandlerBody,
175
- ): AppendValueGroup<Builder> {
176
- const { endpoint, parameters } = args;
177
- const result = appendValueGroup<Builder>([], '\n');
178
-
179
- const requestFunctionName = this.getEndpointRequestFunctionName(ctx, { endpoint });
180
- const parameterNames = parameters.map((p) => toCasing(p.name, ctx.config.parameterNameCasing));
181
-
182
- result.values.push(s`return ${
183
- kt.call([
184
- kt.call(['this', requestFunctionName], parameterNames),
185
- kt.call([kt.refs.springReactive.awaitExchange()], ['responseHandler']),
186
- ])
187
- }`);
188
-
189
- return result;
190
- }
191
-
192
- protected getEndpointRequestFunctionName(ctx: Context, args: Args.GetEndpointRequestFunctionName): string {
193
- const { endpoint } = args;
194
- return toCasing(`${this.getEndpointFunctionName(ctx, { endpoint })}_request`, ctx.config.functionNameCasing);
195
- }
196
-
197
- protected getEndpointRequestFunction(ctx: Context, args: Args.GetEndpointRequestFunction): kt.Function<Builder> {
198
- const { endpoint, parameters, responseSchema } = args;
199
- const functionName = this.getEndpointRequestFunctionName(ctx, { endpoint });
200
-
201
- return kt.function(functionName, {
202
- doc: kt.doc(this.getEndpointDocDescription(ctx, { endpoint })),
203
- receiverType: kt.refs.springReactive.webClient(),
204
- parameters: parameters.map((parameter) =>
205
- kt.parameter(
206
- toCasing(parameter.name, ctx.config.parameterNameCasing),
207
- this.getParameterType(ctx, { endpoint, parameter }),
208
- { default: this.getParameterDefaultValue(ctx, { endpoint, parameter }) },
209
- )
210
- ),
211
- returnType: kt.refs.springReactive.requestHeadersSpec(['*']),
212
- body: this.getEndpointRequestFunctionBody(ctx, { endpoint, parameters, responseSchema }),
213
- });
214
- }
215
-
216
- protected getEndpointRequestFunctionBody(
217
- ctx: Context,
218
- args: Args.GetEndpointRequestFunctionBody,
219
- ): AppendValueGroup<Builder> {
220
- const { endpoint, parameters, responseSchema } = args;
221
- const result = appendValueGroup<Builder>([], '\n');
222
-
223
- const callChain: KtValue<Builder>[] = [];
224
- callChain.push(
225
- s`return this.method(${kt.refs.spring.httpMethod()}.${endpoint.method.toUpperCase()})`,
226
- this.getEndpointUriCall(ctx, { endpoint, parameters }),
227
- );
228
-
229
- if (responseSchema) {
230
- callChain.push(s`accept(${kt.refs.spring.mediaType()}.APPLICATION_JSON)`);
231
- }
232
-
233
- if (endpoint.requestBody?.content[0] !== undefined) {
234
- callChain.push(
235
- s`contentType(${kt.refs.spring.mediaType()}.parseMediaType(${
236
- kt.string(endpoint.requestBody.content[0].type)
237
- }))`,
238
- );
239
- }
240
-
241
- if (endpoint.requestBody?.content[0]) {
242
- if (endpoint.requestBody.content[0].type === 'multipart/form-data') {
243
- callChain.push(
244
- kt.call('body', [
245
- kt.call([kt.refs.springReactive.bodyInserters(), 'fromMultipartData'], [
246
- kt.call([
247
- kt.call(kt.refs.spring.multipartBodyBuilder(), []),
248
- kt.call('apply', [
249
- kt.lambda(
250
- [],
251
- appendValueGroup(
252
- parameters.filter((x) => x.multipart).map((p) => {
253
- const parameterName = toCasing(p.name, ctx.config.parameterNameCasing);
254
- if (p.multipart?.isFile) {
255
- return kt.call([
256
- p.required && !p.schema?.nullable ? parameterName : `${parameterName}?`,
257
- 'addToBuilder',
258
- ], ['this']);
259
- } else {
260
- const call = kt.call([
261
- kt.call('part', [kt.string(p.multipart!.name), parameterName]),
262
- kt.call('contentType', [
263
- kt.call([
264
- kt.refs.spring.mediaType(),
265
- 'APPLICATION_JSON',
266
- ]),
267
- ]),
268
- ]);
269
- return p.required && !p.schema?.nullable ? call : kt.call([`${parameterName}?`, 'also'], [
270
- kt.lambda([parameterName], call, { singleline: true }),
271
- ]);
272
- }
273
- }),
274
- '\n',
275
- ),
276
- ),
277
- ]),
278
- 'build',
279
- ], []),
280
- ]),
281
- ]),
282
- );
283
- } else {
284
- const bodySchema = endpoint.requestBody.content[0].schema;
285
- const parameterName = this.getRequestBodyParamName(ctx, { endpoint });
286
- const call = kt.call('bodyValue', [
287
- toCasing(parameterName, ctx.config.parameterNameCasing),
288
- ]);
289
- callChain.push(
290
- endpoint.requestBody.required && !bodySchema?.nullable ? call : kt.call('apply', [
291
- kt.lambda(
292
- [],
293
- kt.call([`${parameterName}?`, 'also'], [kt.lambda([parameterName], call, { singleline: true })]),
294
- { singleline: true },
295
- ),
296
- ]),
297
- );
298
- }
299
- }
300
-
301
- if (parameters.some((x) => x.target === 'header')) {
302
- callChain.push(
303
- kt.call('headers', [
304
- kt.lambda(
305
- ['headers'],
306
- appendValueGroup(
307
- parameters.filter((x) => x.target === 'header').map((p) => {
308
- const parameterName = toCasing(p.name, ctx.config.parameterNameCasing);
309
- const toString = this.getParameterToString(ctx, { endpoint, parameter: p });
310
- return p.required && !p.schema?.nullable
311
- ? kt.call(['headers', 'add'], [kt.string(p.name), s<Builder>`${parameterName}${toString}`])
312
- : kt.call([`${parameterName}?`, 'also'], [
313
- kt.lambda([], kt.call(['headers', 'add'], [kt.string(p.name), s<Builder>`it${toString}`]), {
314
- singleline: true,
315
- }),
316
- ]);
317
- }),
318
- '\n',
319
- ),
320
- ),
321
- ]),
322
- );
323
- }
324
-
325
- result.values.push(kt.call(callChain));
326
- return result;
327
- }
328
-
329
- /**
330
- * Emits the `uri(...)` call of the request function. If `preserveUriTemplate` is enabled, the URI template is
331
- * passed to `WebClient` verbatim, so Spring can record it (`ClientRequestObservationContext.uriTemplate`) and tag
332
- * `http.client.requests` with the route instead of the expanded path.
333
- */
334
- protected getEndpointUriCall(ctx: Context, args: Args.GetEndpointUriCall): kt.Value<Builder> {
335
- const { endpoint, parameters } = args;
336
-
337
- if (!ctx.config.preserveUriTemplate) {
338
- return kt.call('uri', [kt.call(
339
- [this.getEndpointUriFunctionName(ctx, { endpoint })],
340
- parameters.filter((p) => p.target === 'path' || p.target === 'query').map((p) =>
341
- toCasing(p.name, ctx.config.parameterNameCasing)
342
- ),
343
- )]);
344
- }
345
-
346
- const uriTemplate = kt.string(this.getEndpointPath(ctx, { endpoint }));
347
- const pathVariables = this.getUriPathVariablesValue(ctx, { endpoint });
348
- const queryParameterCalls = this.getUriQueryParameterCalls(ctx, { endpoint });
349
-
350
- // Without query parameters the template and its variables can be handed to `uri` directly.
351
- if (!queryParameterCalls) {
352
- return kt.call('uri', [uriTemplate, pathVariables]);
353
- }
354
-
355
- // Query parameters need a `UriBuilder`, which the `uri(String, Function<UriBuilder, URI>)` overload provides
356
- // while still recording the template.
357
- return kt.call('uri', [
358
- uriTemplate,
359
- kt.lambda(
360
- ['uriBuilder'],
361
- kt.call([
362
- 'uriBuilder',
363
- kt.call('apply', [kt.lambda([], queryParameterCalls)]),
364
- kt.call('build', [pathVariables]),
365
- ]),
366
- ),
367
- ]);
368
- }
369
-
370
- protected getUriPathVariablesValue(ctx: Context, args: Args.GetUriPathVariablesValue): kt.Value<Builder> | null {
371
- const { endpoint } = args;
372
- const pathParameters = endpoint.parameters.filter((p) => p.target === 'path');
373
- if (pathParameters.length === 0) return null;
374
-
375
- return kt.call(
376
- [kt.refs.mapOf.infer()],
377
- pathParameters.map((p) =>
378
- s`${kt.string(p.name)} to ${toCasing(p.name, ctx.config.parameterNameCasing)}${
379
- this.getParameterToString(ctx, { endpoint, parameter: p })
380
- }`
381
- ),
382
- );
383
- }
384
-
385
- protected getUriQueryParameterCalls(
386
- ctx: Context,
387
- args: Args.GetUriQueryParameterCalls,
388
- ): AppendValueGroup<Builder> | null {
389
- const { endpoint } = args;
390
- const queryParameters = endpoint.parameters.filter((p) => p.target === 'query');
391
- if (queryParameters.length === 0) return null;
392
-
393
- return appendValueGroup(
394
- queryParameters.map((p) => {
395
- const parameterName = toCasing(p.name, ctx.config.parameterNameCasing);
396
- const toString = this.getParameterToString(ctx, { endpoint, parameter: p });
397
- return p.required && !p.schema?.nullable
398
- ? kt.call('queryParam', [kt.string(p.name), s<Builder>`${parameterName}${toString}`])
399
- : kt.call([`${parameterName}?`, 'also'], [
400
- kt.lambda([], kt.call('queryParam', [kt.string(p.name), s<Builder>`it${toString}`]), {
401
- singleline: true,
402
- }),
403
- ]);
404
- }),
405
- '\n',
406
- );
407
- }
408
-
409
- protected getEndpointUriFunctionName(ctx: Context, args: Args.GetEndpointUriFunctionName): string {
410
- const { endpoint } = args;
411
- return toCasing(`${this.getEndpointFunctionName(ctx, { endpoint })}_uri`, ctx.config.functionNameCasing);
412
- }
413
-
414
- protected getEndpointUriFunction(ctx: Context, args: Args.GetEndpointUriFunction): kt.Function<Builder> {
415
- const { endpoint, parameters } = args;
416
- const functionName = this.getEndpointUriFunctionName(ctx, { endpoint });
417
-
418
- return kt.function(functionName, {
419
- parameters: parameters.filter((p) => p.target === 'path' || p.target === 'query').map((parameter) =>
420
- kt.parameter(
421
- toCasing(parameter.name, ctx.config.parameterNameCasing),
422
- this.getParameterType(ctx, { endpoint, parameter }),
423
- { default: this.getParameterDefaultValue(ctx, { endpoint, parameter }) },
424
- )
425
- ),
426
- returnType: kt.refs.string(),
427
- body: this.getEndpointUriFunctionBody(ctx, { endpoint, parameters }),
428
- });
429
- }
430
-
431
- protected getEndpointUriFunctionBody(ctx: Context, args: Args.GetEndpointUriFunctionBody): AppendValueGroup<Builder> {
432
- const { endpoint } = args;
433
- const result = appendValueGroup<Builder>([], '\n');
434
-
435
- const callChain: KtValue<Builder>[] = [];
436
- callChain.push(
437
- s`${kt.refs.spring.uriComponentsBuilder()}.fromPath(${kt.string(this.getEndpointPath(ctx, { endpoint }))})`,
438
- );
439
-
440
- const queryParameterCalls = this.getUriQueryParameterCalls(ctx, { endpoint });
441
- if (queryParameterCalls) {
442
- callChain.push(kt.call('apply', [kt.lambda([], queryParameterCalls)]));
443
- }
444
-
445
- const pathVariables = this.getUriPathVariablesValue(ctx, { endpoint });
446
- callChain.push(pathVariables ? kt.call('buildAndExpand', [pathVariables]) : kt.call('build', []));
447
-
448
- callChain.push('toUriString');
449
- result.values.push(s`return ${kt.call(callChain, [])}`);
450
- return result;
451
- }
452
-
453
- protected getParameterToString(ctx: Context, args: Args.GetParameterToString): kt.Value<Builder> {
454
- const { parameter } = args;
455
- if (parameter.schema?.kind === 'array') {
456
- const itemEnumSchema = getArrayItemStringEnumSchema(parameter.schema);
457
- const itemEnumType = itemEnumSchema && this.getSchemaType(ctx, { schema: itemEnumSchema });
458
- return itemEnumType ? s`.joinToString(",", transform = ${itemEnumType}::value)` : '.joinToString(",")';
459
- } else if (
460
- getStringEnumSchema(parameter.schema) && this.getSchemaType(ctx, { schema: parameter.schema })
461
- ) {
462
- return '.value';
463
- } else {
464
- return '.toString()';
465
- }
466
- }
467
-
468
- protected getParameterType(ctx: Context, args: Args.GetParameterType): kt.Type<Builder> {
469
- const { parameter } = args;
470
- if (parameter.multipart?.isFile) {
471
- return ctx.refs.apiRequestFile();
472
- }
473
- return this.getTypeUsage(ctx, {
474
- schema: parameter.schema,
475
- nullable: !parameter.required,
476
- });
477
- }
478
-
479
- protected getParameterDefaultValue(ctx: Context, args: Args.GetParameterDefaultValue): kt.Value<Builder> | null {
480
- const { schema } = args.parameter;
481
-
482
- if (args.parameter.required) {
483
- return null;
484
- }
485
-
486
- if (getStringEnumSchema(schema) && schema?.default) {
487
- return s`${this.getTypeUsage(ctx, { schema, nullable: false })}.${
488
- toCasing(String(schema.default), ctx.config.enumValueNameCasing)
489
- }`;
490
- }
491
-
492
- const itemEnumSchema = getArrayItemStringEnumSchema(schema);
493
- if (itemEnumSchema && Array.isArray(schema?.default)) {
494
- const itemType = this.getTypeUsage(ctx, { schema: itemEnumSchema, nullable: false });
495
- return kt.call(
496
- kt.refs.listOf.infer(),
497
- schema.default.map((x) => s<Builder>`${itemType}.${toCasing(String(x), ctx.config.enumValueNameCasing)}`),
498
- );
499
- }
500
-
501
- return kt.toNode(schema?.default);
502
- }
503
-
504
- protected getTypeUsage(ctx: Context, args: Args.GetTypeUsage<Builder>): kt.Type<Builder> {
505
- const { schema, nullable, fallback } = args;
506
- const type = this.getSchemaType(ctx, { schema });
507
- return type
508
- ? createOverwriteProxy(type, { nullable: nullable ?? type.nullable })
509
- : (fallback ?? kt.refs.any({ nullable }));
510
- }
511
-
512
- // deno-lint-ignore no-unused-vars
513
- protected getPackageName(ctx: Context, args: Args.GetPackageName): string {
514
- const packageSuffix = typeof ctx.config.packageSuffix === 'string'
515
- ? ctx.config.packageSuffix
516
- : ctx.config.packageSuffix(ctx.service);
517
- return ctx.config.packageName + packageSuffix;
518
- }
519
-
520
- protected getResponseSchema(_ctx: Context, args: Args.GetResponseSchema): ApiSchema | undefined {
521
- const { endpoint } = args;
522
- return endpoint.responses.find((x) => !x.statusCode || (x.statusCode >= 200 && x.statusCode < 300))
523
- ?.contentOptions[0]?.schema;
524
- }
525
-
526
- protected getSchemaType(ctx: Context, args: Args.GetSchemaType): kt.Reference<SourceBuilder> | undefined {
527
- const { schema } = args;
528
- return schema && ctx.input.kotlin.models[schema.id].type;
529
- }
530
-
531
- protected getAllParameters(ctx: Context, args: Args.GetAllParameters): ApiParameterWithMultipartInfo[] {
532
- const { endpoint } = args;
533
- const parameters = endpoint.parameters.filter(
534
- (parameter) => parameter.target === 'query' || parameter.target === 'path' || parameter.target === 'header',
535
- );
536
- if (endpoint.requestBody) {
537
- const content = endpoint.requestBody.content[0];
538
- let schema = content.schema;
539
-
540
- if (content.type === 'multipart/form-data') {
541
- if (schema && schema.kind === 'object') {
542
- schema = resolveAnyOfAndAllOf(schema, true) ?? schema;
543
- const properties = schema.properties ?? {};
544
- for (const [name, property] of properties.entries()) {
545
- parameters.push(
546
- Object.assign(
547
- this.createApiParameter({
548
- id: `multipart-${name}`,
549
- name,
550
- target: 'body',
551
- schema: property.schema,
552
- required: schema.required.has(name),
553
- description: property.schema.description,
554
- }),
555
- {
556
- multipart: {
557
- name,
558
- isFile: property.schema.kind === 'string' && property.schema.format === 'binary',
559
- },
560
- },
561
- ),
562
- );
563
- }
564
- }
565
- } else {
566
- parameters.push(
567
- this.createApiParameter({
568
- id: 'body',
569
- name: this.getRequestBodyParamName(ctx, { endpoint }),
570
- target: 'body',
571
- schema,
572
- required: endpoint.requestBody.required,
573
- description: endpoint.requestBody.description,
574
- }),
575
- );
576
- }
577
- }
578
-
579
- return parameters.sort((a, b) => (a.required === b.required ? 0 : a.required ? -1 : 1));
580
- }
581
-
582
- protected getRequestBodyParamName(ctx: Context, args: Args.GetRequestBodyParamName): string {
583
- const { endpoint } = args;
584
- const schema = endpoint.requestBody?.content[0].schema;
585
- const schemaInfo = this.getSchemaType(ctx, { schema });
586
- return toCasing(
587
- schemaInfo && schemaInfo.name !== 'Any' ? SourceBuilder.build((b) => kt.reference.write(b, schemaInfo)) : 'body',
588
- ctx.config.parameterNameCasing,
589
- );
590
- }
591
-
592
- protected getEndpointDocDescription(ctx: Context, args: Args.GetEndpointDocDescription): BasicAppendValue<Builder> {
593
- const docSegments = [args.endpoint.description?.trim()];
594
-
595
- if (ctx.config.includeSourceInDocs) {
596
- docSegments.push(getSourceDocLine(args.endpoint));
597
- }
598
-
599
- return docSegments.filter(notNullish).join('\n\n');
600
- }
601
-
602
- protected getBasePath(ctx: Context, _args: Args.GetBasePath): string {
603
- return modifyString(
604
- (ctx.service.$src ?? ctx.service.endpoints[0]?.$src)?.document.servers?.[0]?.url ?? '/',
605
- ctx.config.basePath,
606
- ctx.service,
607
- );
608
- }
609
-
610
- protected getEndpointPath(ctx: Context, args: Args.GetEndpointPath): string {
611
- const { endpoint } = args;
612
- return modifyString(endpoint.path.replace(/^\/*/, ''), ctx.config.pathModifier, endpoint);
613
- }
614
-
615
- protected getFilePath(ctx: Context, args: Args.GetFilePath): string {
616
- const { packageName } = args;
617
- return `${ctx.config.outputDir}/${packageName.replace(/\./g, '/')}/${this.getRequestsObjectName(ctx, {})}.kt`;
618
- }
619
-
620
- // deno-lint-ignore no-unused-vars
621
- protected getRequestsObjectName(ctx: Context, args: Args.GetRequestsObjectName): string {
622
- return toCasing(`${ctx.service.name}_Requests`, ctx.config.typeNameCasing);
623
- }
624
-
625
- private createApiParameter(data: Partial<ApiParameter> & Pick<ApiParameter, 'id' | 'name' | 'target'>): ApiParameter {
626
- return {
627
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
628
- $src: undefined!,
629
- $ref: undefined,
630
- schema: undefined,
631
- required: false,
632
- description: undefined,
633
- allowEmptyValue: undefined,
634
- allowReserved: undefined,
635
- deprecated: false,
636
- explode: undefined,
637
- style: undefined,
638
- ...data,
639
- };
640
- }
641
- }