@goast/kotlin 0.5.9-beta.2 → 0.5.9

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