@goast/kotlin 0.0.1 → 0.0.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 (22) hide show
  1. package/cjs/lib/generators/index.js +1 -0
  2. package/cjs/lib/generators/models/model-generator.js +77 -25
  3. package/cjs/lib/generators/services/okhttp3-clients/index.js +6 -0
  4. package/cjs/lib/generators/services/okhttp3-clients/models.js +5 -0
  5. package/cjs/lib/generators/services/okhttp3-clients/okhttp3-client-generator.js +404 -0
  6. package/cjs/lib/generators/services/okhttp3-clients/okhttp3-clients-generator.js +48 -0
  7. package/cjs/lib/generators/services/spring-controllers/spring-controller-generator.js +15 -42
  8. package/esm/lib/generators/index.js +1 -0
  9. package/esm/lib/generators/models/model-generator.js +77 -25
  10. package/esm/lib/generators/services/okhttp3-clients/index.js +3 -0
  11. package/esm/lib/generators/services/okhttp3-clients/models.js +2 -0
  12. package/esm/lib/generators/services/okhttp3-clients/okhttp3-client-generator.js +400 -0
  13. package/esm/lib/generators/services/okhttp3-clients/okhttp3-clients-generator.js +44 -0
  14. package/esm/lib/generators/services/spring-controllers/spring-controller-generator.js +15 -42
  15. package/package.json +2 -2
  16. package/types/lib/file-builder.d.ts +1 -1
  17. package/types/lib/generators/index.d.ts +1 -0
  18. package/types/lib/generators/models/model-generator.d.ts +9 -3
  19. package/types/lib/generators/services/okhttp3-clients/index.d.ts +3 -0
  20. package/types/lib/generators/services/okhttp3-clients/models.d.ts +21 -0
  21. package/types/lib/generators/services/okhttp3-clients/okhttp3-client-generator.d.ts +59 -0
  22. package/types/lib/generators/services/okhttp3-clients/okhttp3-clients-generator.d.ts +20 -0
@@ -0,0 +1,400 @@
1
+ import { writeFileSync } from 'fs';
2
+ import { dirname } from 'path';
3
+ import { ensureDirSync } from 'fs-extra';
4
+ import { toCasing } from '@goast/core';
5
+ import { KotlinFileBuilder } from '../../../file-builder';
6
+ import { toKotlinStringLiteral } from '../../../utils';
7
+ import { KotlinFileGenerator } from '../../file-generator';
8
+ export class DefaultKotlinOkHttp3Generator extends KotlinFileGenerator {
9
+ generate(ctx) {
10
+ const packageName = this.getPackageName(ctx);
11
+ const typeName = this.getApiClientName(ctx);
12
+ const filePath = this.getFilePath(ctx, packageName);
13
+ ensureDirSync(dirname(filePath));
14
+ console.log(`Generating client for service ${ctx.service.name} to ${filePath}...`);
15
+ const builder = new KotlinFileBuilder(packageName, ctx.config);
16
+ this.generateApiClientFileContent(ctx, builder);
17
+ writeFileSync(filePath, builder.toString());
18
+ return { typeName, packageName };
19
+ }
20
+ generateApiClientFileContent(ctx, builder) {
21
+ builder
22
+ .apply((builder) => this.generateApiClientClassAnnotations(ctx, builder))
23
+ .ensureCurrentLineEmpty()
24
+ .apply((builder) => this.generateApiClientClassSignature(ctx, builder))
25
+ .append(' ')
26
+ .parenthesizeMultiline('{}', (builder) => this.generateApiClientClassContent(ctx, builder));
27
+ }
28
+ generateApiClientClassAnnotations(ctx, builder) {
29
+ // None for now
30
+ }
31
+ generateApiClientClassSignature(ctx, builder) {
32
+ builder
33
+ .append('class ')
34
+ .append(this.getApiClientName(ctx))
35
+ .parenthesizeMultiline('()', (builder) => builder
36
+ .appendLine('basePath: String = defaultBasePath,')
37
+ .appendLine('client: OkHttpClient = ApiClient.defaultClient')
38
+ .addImport('OkHttpClient', 'okhttp3')
39
+ .addImport('ApiClient', ctx.config.infrastructurePackageName))
40
+ .append(' : ')
41
+ .append('ApiClient(basePath, client)');
42
+ }
43
+ generateApiClientClassContent(ctx, builder) {
44
+ builder
45
+ .apply((builder) => this.generateApiClientCompanionObject(ctx, builder))
46
+ .forEach(ctx.service.endpoints, (builder, endpoint) => builder
47
+ .ensurePreviousLineEmpty()
48
+ .apply((builder) => this.generateApiClientMethod(ctx, builder, endpoint))
49
+ .ensurePreviousLineEmpty()
50
+ .apply((builder) => this.generateApiClientHttpInfoMethod(ctx, builder, endpoint))
51
+ .ensurePreviousLineEmpty()
52
+ .apply((builder) => this.generateApiClientRequestConfigMethod(ctx, builder, endpoint)))
53
+ .ensurePreviousLineEmpty()
54
+ .apply((builder) => this.generateAdditionalMethods(ctx, builder));
55
+ }
56
+ generateApiClientCompanionObject(ctx, builder) {
57
+ builder
58
+ .append('companion object ')
59
+ .parenthesizeMultiline('{}', (builder) => this.generateApiClientCompanionObjectContent(ctx, builder));
60
+ }
61
+ generateApiClientCompanionObjectContent(ctx, builder) {
62
+ this.generateApiClientCompanionObjectDefaultBasePathProperty(ctx, builder);
63
+ }
64
+ generateApiClientCompanionObjectDefaultBasePathProperty(ctx, builder) {
65
+ builder
66
+ .appendAnnotation('JvmStatic')
67
+ .append('val defaultBasePath: String by lazy ')
68
+ .parenthesizeMultiline('{}', (builder) => builder
69
+ .appendLine(`System.getProperties().getProperty(ApiClient.baseUrlKey, ${this.toStringLiteral(ctx, this.getBasePath(ctx))})`)
70
+ .addImport('ApiClient', ctx.config.infrastructurePackageName));
71
+ }
72
+ generateApiClientMethod(ctx, builder, endpoint) {
73
+ builder
74
+ .apply((builder) => this.generateApiClientMethodDocumentation(ctx, builder, endpoint))
75
+ .ensureCurrentLineEmpty()
76
+ .apply((builder) => this.generateApiClientMethodAnnotations(ctx, builder, endpoint))
77
+ .ensureCurrentLineEmpty()
78
+ .apply((builder) => this.generateApiClientMethodSignature(ctx, builder, endpoint))
79
+ .append(' ')
80
+ .parenthesizeMultiline('{}', (builder) => this.generateApiClientMethodContent(ctx, builder, endpoint));
81
+ }
82
+ generateApiClientMethodDocumentation(ctx, builder, endpoint) {
83
+ builder
84
+ .appendLine('/**')
85
+ .applyWithLinePrefix(' * ', (builder) => {
86
+ var _a;
87
+ return builder
88
+ .appendLine(`${(_a = endpoint.summary) !== null && _a !== void 0 ? _a : 'TODO: Provide summary'}`)
89
+ .apply((builder) => this.generateParamDocEntries(ctx, builder, endpoint))
90
+ .append('@return ')
91
+ .apply((builder) => this.generateApiClientMethodReturnType(ctx, builder, endpoint))
92
+ .appendLine()
93
+ .appendLine('@throws IllegalStateException If the request is not correctly configured')
94
+ .appendLine('@throws IOException Rethrows the OkHttp execute method exception')
95
+ .appendLine('@throws UnsupportedOperationException If the API returns an informational or redirection response')
96
+ .appendLine('@throws ClientException If the API returns a client error response')
97
+ .appendLine('@throws ServerException If the API returns a server error response');
98
+ })
99
+ .appendLine(' */');
100
+ }
101
+ generateApiClientMethodAnnotations(ctx, builder, endpoint) {
102
+ const responseSchema = this.getResponseSchema(ctx, endpoint);
103
+ builder
104
+ .applyIf(responseSchema !== undefined, (builder) => builder.appendAnnotation('Supress', undefined, ['"UNCHECKED_CAST"']))
105
+ .appendAnnotation('Throws', undefined, [
106
+ 'IllegalStateException::class',
107
+ 'IOException::class',
108
+ 'UnsupportedOperationException::class',
109
+ 'ClientException::class',
110
+ 'ServerException::class',
111
+ ])
112
+ .addImport('IOException', 'java.io')
113
+ .addImport('ClientException', ctx.config.infrastructurePackageName)
114
+ .addImport('ServerException', ctx.config.infrastructurePackageName);
115
+ }
116
+ generateApiClientMethodSignature(ctx, builder, endpoint) {
117
+ builder
118
+ .append('fun ')
119
+ .append(toCasing(endpoint.name, 'camel'))
120
+ .parenthesize('()', (builder) => this.generateApiClientMethodParameters(ctx, builder, endpoint))
121
+ .append(': ')
122
+ .apply((builder) => this.generateApiClientMethodReturnType(ctx, builder, endpoint));
123
+ }
124
+ generateApiClientMethodParameters(ctx, builder, endpoint) {
125
+ this.generateParams(ctx, builder, endpoint, true);
126
+ }
127
+ generateApiClientMethodReturnType(ctx, builder, endpoint) {
128
+ this.generateTypeUsage(ctx, builder, this.getResponseSchema(ctx, endpoint), 'Unit');
129
+ }
130
+ generateApiClientMethodContent(ctx, builder, endpoint) {
131
+ const responseSchema = this.getResponseSchema(ctx, endpoint);
132
+ builder
133
+ .append(`val localVarResponse = ${toCasing(endpoint.name, 'camel')}HttpInfo`)
134
+ .parenthesize('()', (builder) => this.generateParams(ctx, builder, endpoint, false))
135
+ .appendLine()
136
+ .appendLine()
137
+ .append('return when (localVarResponse.responseType) ')
138
+ .parenthesizeMultiline('{}', (builder) => builder
139
+ .append('ResponseType.Success -> ')
140
+ .applyIfElse(responseSchema === undefined, (builder) => builder.append('Unit'), (builder) => builder
141
+ .append('(localVarResponse as Success<*>).data as ')
142
+ .addImport('Success', ctx.config.infrastructurePackageName)
143
+ .apply((builder) => this.generateTypeUsage(ctx, builder, responseSchema)))
144
+ .ensureCurrentLineEmpty()
145
+ .appendLine(responseErrorHandlingCode)
146
+ .addImport('ClientError', ctx.config.infrastructurePackageName)
147
+ .addImport('ServerError', ctx.config.infrastructurePackageName)
148
+ .addImport('ResponseType', ctx.config.infrastructurePackageName));
149
+ }
150
+ generateApiClientHttpInfoMethod(ctx, builder, endpoint) {
151
+ builder
152
+ .apply((builder) => this.generateApiClientHttpInfoMethodDocumentation(ctx, builder, endpoint))
153
+ .ensureCurrentLineEmpty()
154
+ .apply((builder) => this.generateApiClientHttpInfoMethodAnnotations(ctx, builder, endpoint))
155
+ .ensureCurrentLineEmpty()
156
+ .apply((builder) => this.generateApiClientHttpInfoMethodSignature(ctx, builder, endpoint))
157
+ .append(' ')
158
+ .parenthesizeMultiline('{}', (builder) => this.generateApiClientHttpInfoMethodContent(ctx, builder, endpoint));
159
+ }
160
+ generateApiClientHttpInfoMethodDocumentation(ctx, builder, endpoint) {
161
+ builder
162
+ .appendLine('/**')
163
+ .applyWithLinePrefix(' * ', (builder) => {
164
+ var _a;
165
+ return builder
166
+ .appendLine(`${(_a = endpoint.summary) !== null && _a !== void 0 ? _a : 'TODO: Provide summary'}`)
167
+ .apply((builder) => this.generateParamDocEntries(ctx, builder, endpoint))
168
+ .append('@return ')
169
+ .apply((builder) => this.generateApiClientHttpInfoMethodReturnType(ctx, builder, endpoint))
170
+ .appendLine()
171
+ .appendLine('@throws IllegalStateException If the request is not correctly configured')
172
+ .appendLine('@throws IOException Rethrows the OkHttp execute method exception')
173
+ .appendLine('@throws UnsupportedOperationException If the API returns an informational or redirection response')
174
+ .appendLine('@throws ClientException If the API returns a client error response')
175
+ .appendLine('@throws ServerException If the API returns a server error response');
176
+ })
177
+ .appendLine(' */');
178
+ }
179
+ generateApiClientHttpInfoMethodAnnotations(ctx, builder, endpoint) {
180
+ builder
181
+ .appendAnnotation('Throws', undefined, ['IllegalStateException::class', 'IOException::class'])
182
+ .addImport('IOException', 'java.io');
183
+ }
184
+ generateApiClientHttpInfoMethodSignature(ctx, builder, endpoint) {
185
+ builder
186
+ .append('fun ')
187
+ .append(toCasing(endpoint.name, 'camel'), 'HttpInfo')
188
+ .parenthesize('()', (builder) => this.generateApiClientHttpInfoMethodSignatureParameters(ctx, builder, endpoint))
189
+ .append(': ')
190
+ .apply((builder) => this.generateApiClientHttpInfoMethodReturnType(ctx, builder, endpoint));
191
+ }
192
+ generateApiClientHttpInfoMethodSignatureParameters(ctx, builder, endpoint) {
193
+ this.generateParams(ctx, builder, endpoint, true);
194
+ }
195
+ generateApiClientHttpInfoMethodReturnType(ctx, builder, endpoint) {
196
+ builder
197
+ .append('ApiResponse')
198
+ .addImport('ApiResponse', ctx.config.infrastructurePackageName)
199
+ .parenthesize('<>', (builder) => this.generateTypeUsage(ctx, builder, this.getResponseSchema(ctx, endpoint), 'Unit'));
200
+ }
201
+ generateApiClientHttpInfoMethodContent(ctx, builder, endpoint) {
202
+ builder
203
+ .append(`val localVariableConfig = ${toCasing(endpoint.name, 'camel')}RequestConfig`)
204
+ .parenthesize('()', (builder) => this.generateParams(ctx, builder, endpoint, false))
205
+ .appendLine()
206
+ .appendLine()
207
+ .append('return request')
208
+ .parenthesize('<>', (builder) => builder
209
+ .apply((builder) => { var _a; return this.generateTypeUsage(ctx, builder, (_a = endpoint.requestBody) === null || _a === void 0 ? void 0 : _a.content[0].schema, 'Unit'); })
210
+ .append(', ')
211
+ .apply((builder) => this.generateTypeUsage(ctx, builder, this.getResponseSchema(ctx, endpoint), 'Unit')))
212
+ .parenthesizeMultiline('()', (builder) => builder.append('localVariableConfig'));
213
+ }
214
+ generateApiClientRequestConfigMethod(ctx, builder, endpoint) {
215
+ builder
216
+ .apply((builder) => this.generateApiClientRequestConfigMethodDocumentation(ctx, builder, endpoint))
217
+ .ensureCurrentLineEmpty()
218
+ .apply((builder) => this.generateApiClientRequestConfigMethodAnnotations(ctx, builder, endpoint))
219
+ .ensureCurrentLineEmpty()
220
+ .apply((builder) => this.generateApiClientRequestConfigMethodSignature(ctx, builder, endpoint))
221
+ .append(' ')
222
+ .parenthesizeMultiline('{}', (builder) => this.generateApiClientRequestConfigMethodContent(ctx, builder, endpoint));
223
+ }
224
+ generateApiClientRequestConfigMethodDocumentation(ctx, builder, endpoint) {
225
+ builder
226
+ .appendLine('/**')
227
+ .applyWithLinePrefix(' * ', (builder) => builder
228
+ .appendLine(`To obtain the request config of the operation ${toCasing(endpoint.name, 'camel')}`)
229
+ .apply((builder) => this.generateParamDocEntries(ctx, builder, endpoint))
230
+ .append('@return RequestConfig'))
231
+ .appendLine(' */');
232
+ }
233
+ generateApiClientRequestConfigMethodAnnotations(ctx, builder, endpoint) {
234
+ // No annotations needed
235
+ }
236
+ generateApiClientRequestConfigMethodSignature(ctx, builder, endpoint) {
237
+ builder
238
+ .append('private fun ')
239
+ .append(toCasing(endpoint.name, 'camel'), 'RequestConfig')
240
+ .parenthesize('()', (builder) => this.generateApiClientRequestConfigMethodSignatureParameters(ctx, builder, endpoint))
241
+ .append(': ')
242
+ .apply((builder) => this.generateApiClientRequestConfigMethodReturnType(ctx, builder, endpoint));
243
+ }
244
+ generateApiClientRequestConfigMethodSignatureParameters(ctx, builder, endpoint) {
245
+ this.generateParams(ctx, builder, endpoint, true);
246
+ }
247
+ generateApiClientRequestConfigMethodReturnType(ctx, builder, endpoint) {
248
+ builder
249
+ .append('RequestConfig')
250
+ .addImport('RequestConfig', ctx.config.infrastructurePackageName)
251
+ .parenthesize('<>', (builder) => { var _a; return this.generateTypeUsage(ctx, builder, (_a = endpoint.requestBody) === null || _a === void 0 ? void 0 : _a.content[0].schema, 'Unit'); });
252
+ }
253
+ generateApiClientRequestConfigMethodContent(ctx, builder, endpoint) {
254
+ var _a, _b;
255
+ builder
256
+ .appendLine(`val localVariableBody = ${this.getRequestBodyParamName(ctx, endpoint)}`)
257
+ .appendLine('val localVariableQuery: MultiValueMap = mutableMapOf()')
258
+ .addImport('MultiValueMap', ctx.config.infrastructurePackageName)
259
+ .forEach(endpoint.parameters.filter((x) => x.target === 'query'), (builder, param) => builder.appendLine(`localVariableQuery["${param.name}"] = ${toCasing(param.name, 'camel')}`))
260
+ .appendLine('val localVariableHeaders: MutableMap<String, String> = mutableMapOf()')
261
+ .appendLineIf(((_a = endpoint.requestBody) === null || _a === void 0 ? void 0 : _a.content[0]) !== undefined, `localVariableHeaders["Content-Type"] = "${(_b = endpoint.requestBody) === null || _b === void 0 ? void 0 : _b.content[0].type}"`)
262
+ .appendLine()
263
+ .append('return RequestConfig')
264
+ .addImport('RequestConfig', ctx.config.infrastructurePackageName)
265
+ .parenthesizeMultiline('()', (builder) => builder
266
+ .appendLine(`method = RequestMethod.${endpoint.method.toUpperCase()},`)
267
+ .addImport('RequestMethod', ctx.config.infrastructurePackageName)
268
+ .appendLine(`path = "${this.getPathWithInterpolation(ctx, endpoint)}",`)
269
+ .appendLine('query = localVariableQuery,')
270
+ .appendLine('headers = localVariableHeaders,')
271
+ .appendLine('requiresAuthentication = false,')
272
+ .appendLine('body = localVariableBody'));
273
+ }
274
+ generateAdditionalMethods(ctx, builder) {
275
+ this.generateEncodeUriComponentMethod(ctx, builder);
276
+ }
277
+ generateEncodeUriComponentMethod(ctx, builder) {
278
+ builder
279
+ .appendLine('private fun encodeURIComponent(uriComponent: String): String =')
280
+ .indent('HttpUrl.Builder().scheme("http").host("localhost").addPathSegment(uriComponent).build().encodedPathSegments[0]')
281
+ .addImport('HttpUrl', 'okhttp3');
282
+ }
283
+ generateParamDocEntries(ctx, builder, endpoint) {
284
+ const parameters = this.getAllParameters(ctx, endpoint);
285
+ builder.forEach(parameters, (builder, parameter) => { var _a; return builder.appendLine(`@param ${parameter.name} ${(_a = parameter.description) !== null && _a !== void 0 ? _a : 'TODO: Provide description'}`); });
286
+ }
287
+ generateParams(ctx, builder, endpoint, includeTypeDefinition) {
288
+ const parameters = this.getAllParameters(ctx, endpoint);
289
+ builder.forEachSeparated(parameters, ', ', (builder, parameter) => builder.append(toCasing(parameter.name, 'camel')).applyIf(includeTypeDefinition, (builder) => builder
290
+ .append(': ')
291
+ .apply((builder) => this.generateTypeUsage(ctx, builder, parameter.schema))
292
+ .appendIf(!parameter.required, '? = ', this.getDefaultValue(ctx, parameter.schema))));
293
+ }
294
+ generateTypeUsage(ctx, builder, schema, fallback) {
295
+ if (schema && schema.kind === 'array') {
296
+ const schemaInfo = this.getSchemaInfo(ctx, schema.items);
297
+ builder.append(`List<${schemaInfo.typeName}>`);
298
+ builder.imports.addImports([schemaInfo, ...schemaInfo.additionalImports]);
299
+ }
300
+ else if (schema || !fallback) {
301
+ const schemaInfo = this.getSchemaInfo(ctx, schema);
302
+ builder.append(schemaInfo.typeName);
303
+ builder.imports.addImports([schemaInfo, ...schemaInfo.additionalImports]);
304
+ }
305
+ else {
306
+ builder.append(fallback);
307
+ }
308
+ }
309
+ getDefaultValue(ctx, schema) {
310
+ if (!(schema === null || schema === void 0 ? void 0 : schema.default)) {
311
+ return 'null';
312
+ }
313
+ if (typeof schema.default === 'string') {
314
+ return toKotlinStringLiteral(schema.default);
315
+ }
316
+ else if (typeof schema.default === 'number' || typeof schema.default === 'boolean') {
317
+ return schema.default.toString();
318
+ }
319
+ else {
320
+ return 'null';
321
+ }
322
+ }
323
+ getPathWithInterpolation(ctx, endpoint) {
324
+ let path = endpoint.path;
325
+ endpoint.parameters
326
+ .filter((x) => x.target === 'path')
327
+ .forEach((parameter) => {
328
+ path = path.replace(`{${parameter.name}}`, `\${encodeURIComponent(${toCasing(parameter.name, 'camel')}.toString())}`);
329
+ });
330
+ return path;
331
+ }
332
+ getResponseSchema(ctx, endpoint) {
333
+ var _a, _b;
334
+ return (_b = (_a = endpoint.responses.find((x) => !x.statusCode || (x.statusCode >= 200 && x.statusCode < 300))) === null || _a === void 0 ? void 0 : _a.contentOptions[0]) === null || _b === void 0 ? void 0 : _b.schema;
335
+ }
336
+ getSchemaInfo(ctx, schema) {
337
+ var _a;
338
+ return ((_a = (schema && ctx.input.models[schema.id])) !== null && _a !== void 0 ? _a : { typeName: 'Any?', packageName: undefined, additionalImports: [] });
339
+ }
340
+ getAllParameters(ctx, endpoint) {
341
+ const parameters = endpoint.parameters.filter((parameter) => parameter.target === 'query' || parameter.target === 'path');
342
+ if (endpoint.requestBody) {
343
+ const schema = endpoint.requestBody.content[0].schema;
344
+ parameters.push({
345
+ $src: undefined,
346
+ $ref: undefined,
347
+ id: 'body',
348
+ name: this.getRequestBodyParamName(ctx, endpoint),
349
+ target: 'body',
350
+ schema,
351
+ required: endpoint.requestBody.required,
352
+ description: endpoint.requestBody.description,
353
+ allowEmptyValue: undefined,
354
+ allowReserved: undefined,
355
+ deprecated: false,
356
+ explode: undefined,
357
+ style: undefined,
358
+ });
359
+ }
360
+ return parameters.sort((a, b) => (a.required === b.required ? 0 : a.required ? -1 : 1));
361
+ }
362
+ getRequestBodyParamName(ctx, endpoint) {
363
+ var _a;
364
+ const schema = (_a = endpoint.requestBody) === null || _a === void 0 ? void 0 : _a.content[0].schema;
365
+ const schemaInfo = this.getSchemaInfo(ctx, schema);
366
+ return /^Any\??$/.test(schemaInfo.typeName) ? 'body' : schemaInfo.typeName;
367
+ }
368
+ getBasePath(ctx) {
369
+ var _a, _b, _c, _d, _e, _f;
370
+ return (_f = (_e = (_d = (_c = ((_a = ctx.service.$src) !== null && _a !== void 0 ? _a : (_b = ctx.service.endpoints[0]) === null || _b === void 0 ? void 0 : _b.$src)) === null || _c === void 0 ? void 0 : _c.document.servers) === null || _d === void 0 ? void 0 : _d[0]) === null || _e === void 0 ? void 0 : _e.url) !== null && _f !== void 0 ? _f : '/';
371
+ }
372
+ getFilePath(ctx, packageName) {
373
+ return `${ctx.config.outputDir}/${packageName.replace(/\./g, '/')}/${this.getApiClientName(ctx)}.kt`;
374
+ }
375
+ getPackageName(ctx) {
376
+ return ctx.config.packageName + ctx.config.packageSuffix;
377
+ }
378
+ getApiClientName(ctx) {
379
+ return toCasing(ctx.service.name, 'pascal') + 'ApiClient';
380
+ }
381
+ }
382
+ const responseErrorHandlingCode = `ResponseType.Informational -> throw UnsupportedOperationException("Client does not support Informational responses.")
383
+ ResponseType.Redirection -> throw UnsupportedOperationException("Client does not support Redirection responses.")
384
+ ResponseType.ClientError -> {
385
+ val localVarError = localVarResponse as ClientError<*>
386
+ throw ClientException(
387
+ "Client error : \${localVarError.statusCode} \${localVarError.message.orEmpty()}",
388
+ localVarError.statusCode,
389
+ localVarResponse
390
+ )
391
+ }
392
+
393
+ ResponseType.ServerError -> {
394
+ val localVarError = localVarResponse as ServerError<*>
395
+ throw ServerException(
396
+ "Server error : \${localVarError.statusCode} \${localVarError.message.orEmpty()}",
397
+ localVarError.statusCode,
398
+ localVarResponse
399
+ )
400
+ }`;
@@ -0,0 +1,44 @@
1
+ import { writeFileSync } from 'fs';
2
+ import { dirname, resolve } from 'path';
3
+ import { ensureDirSync, readFileSync, readdirSync } from 'fs-extra';
4
+ import { Factory, OpenApiServicesGenerationProviderBase } from '@goast/core';
5
+ import { defaultKotlinOkHttp3ClientsGeneratorConfig, } from './models';
6
+ import { DefaultKotlinOkHttp3Generator } from './okhttp3-client-generator';
7
+ export class KotlinOkHttp3ClientsGenerator extends OpenApiServicesGenerationProviderBase {
8
+ constructor(serviceGeneratorFactory) {
9
+ super();
10
+ this._serviceGeneratorFactory = serviceGeneratorFactory !== null && serviceGeneratorFactory !== void 0 ? serviceGeneratorFactory : Factory.fromValue(new DefaultKotlinOkHttp3Generator());
11
+ }
12
+ onGenerate(ctx) {
13
+ this.copyInfrastructureFiles(ctx);
14
+ return super.onGenerate(ctx);
15
+ }
16
+ initResult() {
17
+ return {
18
+ clients: {},
19
+ };
20
+ }
21
+ generateService(ctx, service) {
22
+ const serviceGenerator = this._serviceGeneratorFactory.create();
23
+ return serviceGenerator.generate(Object.assign(Object.assign({}, ctx), { service }));
24
+ }
25
+ addServiceResult(ctx, service, result) {
26
+ ctx.output.clients[service.id] = result;
27
+ }
28
+ buildContext(context, config) {
29
+ context.data.services = context.data.services.filter((x) => x.name !== 'exclude-from-generation');
30
+ return this.getProviderContext(context, config, defaultKotlinOkHttp3ClientsGeneratorConfig);
31
+ }
32
+ copyInfrastructureFiles(ctx) {
33
+ const sourceDir = resolve(dirname(require.resolve('@goast/kotlin')), '../assets/client/okhttp3');
34
+ const targetDir = resolve(ctx.config.outputDir, ctx.config.infrastructurePackageName.replace(/\./g, '/'));
35
+ ensureDirSync(targetDir);
36
+ const files = readdirSync(sourceDir);
37
+ for (const file of files) {
38
+ const fileContent = readFileSync(resolve(sourceDir, file))
39
+ .toString()
40
+ .replace(/@PACKAGE_NAME@/g, ctx.config.infrastructurePackageName);
41
+ writeFileSync(resolve(targetDir, file), fileContent);
42
+ }
43
+ }
44
+ }
@@ -30,10 +30,7 @@ export class DefaultKotlinSpringControllerGenerator extends KotlinFileGenerator
30
30
  .ensureCurrentLineEmpty()
31
31
  .apply((builder) => this.generateApiInterfaceSignature(ctx, builder))
32
32
  .append(' ')
33
- .parenthesize('{}', (builder) => builder
34
- .appendLine()
35
- .apply((builder) => this.generateApiInterfaceContent(ctx, builder))
36
- .ensureCurrentLineEmpty());
33
+ .parenthesizeMultiline('{}', (builder) => this.generateApiInterfaceContent(ctx, builder));
37
34
  }
38
35
  generateApiInterfaceAnnotations(ctx, builder) {
39
36
  builder
@@ -63,10 +60,7 @@ export class DefaultKotlinSpringControllerGenerator extends KotlinFileGenerator
63
60
  .ensureCurrentLineEmpty()
64
61
  .apply((builder) => this.generateApiInterfaceMethodSignature(ctx, builder, endpoint))
65
62
  .append(' ')
66
- .parenthesize('{}', (builder) => builder
67
- .appendLine()
68
- .apply((builder) => this.generateApiInterfaceMethodContent(ctx, builder, endpoint))
69
- .appendLine());
63
+ .parenthesizeMultiline('{}', (builder) => this.generateApiInterfaceMethodContent(ctx, builder, endpoint));
70
64
  }
71
65
  generateApiInterfaceMethodAnnnotations(ctx, builder, endpoint) {
72
66
  var _a, _b, _c;
@@ -77,9 +71,7 @@ export class DefaultKotlinSpringControllerGenerator extends KotlinFileGenerator
77
71
  ['description', this.toStringLiteral(ctx, (_b = endpoint.description) === null || _b === void 0 ? void 0 : _b.trim())],
78
72
  [
79
73
  'responses',
80
- (builder) => builder.parenthesize('[]', (builder) => builder
81
- .appendLine()
82
- .forEachSeparated(endpoint.responses, ',\n', (builder, response) => builder
74
+ (builder) => builder.parenthesizeMultiline('[]', (builder) => builder.forEachSeparated(endpoint.responses, ',\n', (builder, response) => builder
83
75
  .append('ApiResponse')
84
76
  .addImport('ApiResponse', 'io.swagger.v3.oas.annotations.responses')
85
77
  .parenthesize('()', (builder) => {
@@ -87,8 +79,7 @@ export class DefaultKotlinSpringControllerGenerator extends KotlinFileGenerator
87
79
  return builder
88
80
  .append(`responseCode = ${this.toStringLiteral(ctx, (_a = response.statusCode) === null || _a === void 0 ? void 0 : _a.toString())}, `)
89
81
  .append(`description = ${this.toStringLiteral(ctx, (_b = response.description) === null || _b === void 0 ? void 0 : _b.trim())}`);
90
- }))
91
- .appendLine()),
82
+ }))),
92
83
  endpoint.responses.length > 0,
93
84
  ],
94
85
  ])
@@ -106,10 +97,7 @@ export class DefaultKotlinSpringControllerGenerator extends KotlinFileGenerator
106
97
  generateApiInterfaceMethodSignature(ctx, builder, endpoint) {
107
98
  builder
108
99
  .append(`suspend fun ${toCasing(endpoint.name, 'camel')}`)
109
- .parenthesize('()', (builder) => builder
110
- .appendLine()
111
- .apply((builder) => this.generateApiInterfaceMethodParameters(ctx, builder, endpoint))
112
- .appendLine())
100
+ .parenthesizeMultiline('()', (builder) => this.generateApiInterfaceMethodParameters(ctx, builder, endpoint))
113
101
  .append(': ')
114
102
  .apply((builder) => this.generateApiInterfaceMethodReturnType(ctx, builder, endpoint));
115
103
  }
@@ -194,10 +182,7 @@ export class DefaultKotlinSpringControllerGenerator extends KotlinFileGenerator
194
182
  .ensureCurrentLineEmpty()
195
183
  .apply((builder) => this.generateApiControllerSignature(ctx, builder))
196
184
  .append(' ')
197
- .parenthesize('{}', (builder) => builder
198
- .appendLine()
199
- .apply((builder) => this.generateApiControllerContent(ctx, builder))
200
- .ensureCurrentLineEmpty());
185
+ .parenthesizeMultiline('{}', (builder) => this.generateApiControllerContent(ctx, builder));
201
186
  }
202
187
  generateApiControllerAnnotations(ctx, builder) {
203
188
  builder
@@ -213,10 +198,7 @@ export class DefaultKotlinSpringControllerGenerator extends KotlinFileGenerator
213
198
  builder
214
199
  .append('class ')
215
200
  .append(this.getApiControllerName(ctx))
216
- .parenthesize('()', (builder) => builder
217
- .appendLine()
218
- .apply((builder) => this.generateApiControllerParameters(ctx, builder))
219
- .ensureCurrentLineEmpty())
201
+ .parenthesizeMultiline('()', (builder) => this.generateApiControllerParameters(ctx, builder))
220
202
  .append(' : ')
221
203
  .append(this.getApiInterfaceName(ctx));
222
204
  }
@@ -233,12 +215,10 @@ export class DefaultKotlinSpringControllerGenerator extends KotlinFileGenerator
233
215
  .appendLine(this.getApiDelegateInterfaceName(ctx))
234
216
  .appendLine()
235
217
  .append('init ')
236
- .parenthesize('{}', (builder) => builder
237
- .appendLine()
218
+ .parenthesizeMultiline('{}', (builder) => builder
238
219
  .append('this.delegate = Optional.ofNullable(delegate).orElse')
239
220
  .addImport('Optional', 'java.util')
240
- .parenthesize('()', (builder) => builder.append('object : ').append(this.getApiDelegateInterfaceName(ctx)).append(' {}'))
241
- .appendLine())
221
+ .parenthesize('()', (builder) => builder.append('object : ').append(this.getApiDelegateInterfaceName(ctx)).append(' {}')))
242
222
  .appendLine()
243
223
  .appendLine()
244
224
  .appendLine(`override fun getDelegate(): ${this.getApiDelegateInterfaceName(ctx)} = delegate`);
@@ -259,10 +239,7 @@ export class DefaultKotlinSpringControllerGenerator extends KotlinFileGenerator
259
239
  .ensureCurrentLineEmpty()
260
240
  .apply((builder) => this.generateApiDelegateInterfaceSignature(ctx, builder))
261
241
  .append(' ')
262
- .parenthesize('{}', (builder) => builder
263
- .appendLine()
264
- .apply((builder) => this.generateApiDelegateInterfaceContent(ctx, builder))
265
- .ensureCurrentLineEmpty());
242
+ .parenthesizeMultiline('{}', (builder) => this.generateApiDelegateInterfaceContent(ctx, builder));
266
243
  }
267
244
  generateApiDelegateInterfaceAnnotations(ctx, builder) {
268
245
  builder.appendAnnotation('Generated', 'jakarta.annotation', [
@@ -287,10 +264,7 @@ export class DefaultKotlinSpringControllerGenerator extends KotlinFileGenerator
287
264
  .ensureCurrentLineEmpty()
288
265
  .apply((builder) => this.generateApiDelegateInterfaceMethodSignature(ctx, builder, endpoint))
289
266
  .append(' ')
290
- .parenthesize('{}', (builder) => builder
291
- .appendLine()
292
- .apply((builder) => this.generateApiDelegateInterfaceMethodContent(ctx, builder, endpoint))
293
- .ensureCurrentLineEmpty());
267
+ .parenthesizeMultiline('{}', (builder) => this.generateApiDelegateInterfaceMethodContent(ctx, builder, endpoint));
294
268
  }
295
269
  generateApiDelegateInterfaceMethodAnnnotations(ctx, builder, endpoint) {
296
270
  // None for now.
@@ -298,10 +272,7 @@ export class DefaultKotlinSpringControllerGenerator extends KotlinFileGenerator
298
272
  generateApiDelegateInterfaceMethodSignature(ctx, builder, endpoint) {
299
273
  builder
300
274
  .append(`suspend fun ${toCasing(endpoint.name, 'camel')}`)
301
- .parenthesize('()', (builder) => builder
302
- .appendLine()
303
- .apply((builder) => this.generateApiDelegateInterfaceMethodParameters(ctx, builder, endpoint))
304
- .appendLine())
275
+ .parenthesizeMultiline('()', (builder) => this.generateApiDelegateInterfaceMethodParameters(ctx, builder, endpoint))
305
276
  .append(': ')
306
277
  .apply((builder) => this.generateApiDelegateInterfaceMethodReturnType(ctx, builder, endpoint));
307
278
  }
@@ -384,11 +355,13 @@ export class DefaultKotlinSpringControllerGenerator extends KotlinFileGenerator
384
355
  const parameters = endpoint.parameters.filter((parameter) => parameter.target === 'query' || parameter.target === 'path');
385
356
  if (endpoint.requestBody) {
386
357
  const schema = endpoint.requestBody.content[0].schema;
358
+ const schemaInfo = this.getSchemaInfo(ctx, schema);
359
+ const name = /^Any\??$/.test(schemaInfo.typeName) ? 'body' : schemaInfo.typeName;
387
360
  parameters.push({
388
361
  $src: undefined,
389
362
  $ref: undefined,
390
363
  id: 'body',
391
- name: schema ? this.getSchemaInfo(ctx, schema).typeName : 'body',
364
+ name,
392
365
  target: 'body',
393
366
  schema,
394
367
  required: endpoint.requestBody.required,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@goast/kotlin",
3
- "version": "0.0.1",
3
+ "version": "0.0.2",
4
4
  "repository": "https://github.com/MaSch0212/goast.git",
5
5
  "author": {
6
6
  "name": "Marc Schmidt (MaSch0212)",
@@ -12,7 +12,7 @@
12
12
  "fs-extra": "^11.1.1",
13
13
  "node-fetch": "^2.6.11",
14
14
  "yaml": "^2.3.1",
15
- "@goast/core": "0.0.5",
15
+ "@goast/core": "0.0.6",
16
16
  "tslib": "^2.3.0"
17
17
  },
18
18
  "module": "./esm/index.js",
@@ -7,7 +7,7 @@ export declare class KotlinFileBuilder extends SourceBuilder {
7
7
  readonly imports: ImportCollection;
8
8
  constructor(packageName: string | undefined, options: SourceBuilderOptions);
9
9
  addImport(name: string, packageName?: string): this;
10
- appendAnnotation(name: string, packageName: string | undefined, args?: AnnotationArgument<this>[]): this;
10
+ appendAnnotation(name: string, packageName?: string, args?: AnnotationArgument<this>[]): this;
11
11
  clear(): void;
12
12
  toString(addPadding?: boolean): string;
13
13
  }
@@ -1,3 +1,4 @@
1
1
  export * from './file-generator';
2
2
  export * from './models';
3
+ export * from './services/okhttp3-clients';
3
4
  export * from './services/spring-controllers';
@@ -12,11 +12,16 @@ export declare class DefaultKotlinModelGenerator extends KotlinFileGenerator<Con
12
12
  generate(ctx: KotlinModelGeneratorContext): KotlinModelGeneratorOutput;
13
13
  protected generateFileContent(ctx: Context, builder: Builder): void;
14
14
  protected generateObjectType(ctx: Context, builder: Builder, schema: ApiSchema<'object'>): void;
15
- protected generateDataClass(ctx: Context, builder: Builder, schema: ApiSchema<'object'>): void;
16
- protected generatePropertyAnnotations(ctx: Context, builder: Builder, schema: ApiSchema, property: ApiSchemaProperty): void;
15
+ protected generateObjectPackageMember(ctx: Context, builder: Builder, schema: ApiSchema<'object'>): void;
16
+ protected generateObjectInterface(ctx: Context, builder: Builder, schema: ApiSchema<'object'>): void;
17
+ protected generateObjectInterfaceAnnotations(ctx: Context, builder: Builder, schema: ApiSchema<'object'>): void;
18
+ protected generateObjectInterfaceSignature(ctx: Context, builder: Builder, schema: ApiSchema<'object'>): void;
19
+ protected generateObjectInterfaceMembers(ctx: Context, builder: Builder, schema: ApiSchema<'object'>): void;
20
+ protected generateObjectDataClass(ctx: Context, builder: Builder, schema: ApiSchema<'object'>): void;
21
+ protected generateObjectDataClassParameterAnnotations(ctx: Context, builder: Builder, schema: ApiSchema, property: ApiSchemaProperty): void;
17
22
  protected generatePropertyValidationAnnotations(ctx: Context, builder: Builder, schema: ApiSchema, property: ApiSchemaProperty): void;
18
23
  protected generatePropertySchemaAnnotation(ctx: Context, builder: Builder, schema: ApiSchema, property: ApiSchemaProperty): void;
19
- protected generateJsonPropertyAnnotation(ctx: Context, builder: Builder, schema: ApiSchema, property: ApiSchemaProperty): void;
24
+ protected generateJsonPropertyAnnotation(ctx: Context, builder: Builder, schema: ApiSchema, property: ApiSchemaProperty, scope?: string): void;
20
25
  protected generateMapType(ctx: Context, builder: Builder, schema: ApiSchema<'object'>): void;
21
26
  protected generateType(ctx: Context, builder: Builder, schema: ApiSchema): void;
22
27
  protected generateNumberType(ctx: Context, builder: Builder, schema: ApiSchema<'number' | 'integer'>): void;
@@ -27,5 +32,6 @@ export declare class DefaultKotlinModelGenerator extends KotlinFileGenerator<Con
27
32
  protected shouldGenerateTypeDeclaration(ctx: Context, schema: ApiSchema): boolean;
28
33
  protected getDeclarationTypeName(ctx: Context): string;
29
34
  protected sortProperties(ctx: Context, schema: ApiSchema, properties: Iterable<ApiSchemaProperty>): ApiSchemaProperty[];
35
+ private hasProperty;
30
36
  }
31
37
  export {};
@@ -0,0 +1,3 @@
1
+ export * from './models';
2
+ export * from './okhttp3-client-generator';
3
+ export * from './okhttp3-clients-generator';