@goast/kotlin 0.3.2 → 0.3.4

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 (29) hide show
  1. package/cjs/index.js +3 -2
  2. package/cjs/lib/ast/references/java.js +5 -4
  3. package/cjs/lib/ast/references/reactor.js +2 -1
  4. package/cjs/lib/ast/references/spring.js +15 -12
  5. package/cjs/lib/generators/models/model-generator.js +9 -18
  6. package/cjs/lib/generators/models/models.js +1 -0
  7. package/cjs/lib/generators/services/okhttp3-clients/okhttp3-client-generator.js +94 -33
  8. package/cjs/lib/generators/services/spring-controllers/spring-controller-generator.js +67 -24
  9. package/cjs/lib/types.js +2 -0
  10. package/esm/index.js +3 -2
  11. package/esm/lib/ast/references/java.js +4 -3
  12. package/esm/lib/ast/references/reactor.js +1 -0
  13. package/esm/lib/ast/references/spring.js +14 -11
  14. package/esm/lib/generators/models/model-generator.js +9 -18
  15. package/esm/lib/generators/models/models.js +1 -0
  16. package/esm/lib/generators/services/okhttp3-clients/okhttp3-client-generator.js +95 -34
  17. package/esm/lib/generators/services/spring-controllers/spring-controller-generator.js +68 -25
  18. package/esm/lib/types.js +1 -0
  19. package/package.json +2 -2
  20. package/types/index.d.ts +3 -2
  21. package/types/lib/ast/references/java.d.ts +16 -3
  22. package/types/lib/ast/references/reactor.d.ts +16 -0
  23. package/types/lib/ast/references/spring.d.ts +44 -18
  24. package/types/lib/generators/models/models.d.ts +33 -0
  25. package/types/lib/generators/services/okhttp3-clients/args.d.ts +9 -0
  26. package/types/lib/generators/services/okhttp3-clients/okhttp3-client-generator.d.ts +6 -2
  27. package/types/lib/generators/services/spring-controllers/args.d.ts +3 -2
  28. package/types/lib/generators/services/spring-controllers/spring-controller-generator.d.ts +4 -2
  29. package/types/lib/types.d.ts +7 -0
package/cjs/index.js CHANGED
@@ -1,10 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const tslib_1 = require("tslib");
4
+ tslib_1.__exportStar(require("./lib/ast"), exports);
4
5
  tslib_1.__exportStar(require("./lib/common-results"), exports);
5
6
  tslib_1.__exportStar(require("./lib/config"), exports);
6
- tslib_1.__exportStar(require("./lib/generators"), exports);
7
7
  tslib_1.__exportStar(require("./lib/file-builder"), exports);
8
+ tslib_1.__exportStar(require("./lib/generators"), exports);
8
9
  tslib_1.__exportStar(require("./lib/import-collection"), exports);
10
+ tslib_1.__exportStar(require("./lib/types"), exports);
9
11
  tslib_1.__exportStar(require("./lib/utils"), exports);
10
- tslib_1.__exportStar(require("./lib/ast"), exports);
@@ -1,13 +1,14 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.optional = exports.offsetDateTime = exports.ioException = exports.unsupportedOperationException = exports.illegalStateException = exports.system = void 0;
3
+ exports.optional = exports.offsetDateTime = exports.unsupportedOperationException = exports.system = exports.illegalStateException = exports.ioException = exports.file = void 0;
4
4
  const reference_1 = require("../nodes/reference");
5
+ // java.io
6
+ exports.file = reference_1.ktReference.factory('File', 'java.io');
7
+ exports.ioException = reference_1.ktReference.factory('IOException', 'java.io');
5
8
  // java.lang
6
- exports.system = reference_1.ktReference.factory('System', 'java.lang');
7
9
  exports.illegalStateException = reference_1.ktReference.factory('IllegalStateException', 'java.lang');
10
+ exports.system = reference_1.ktReference.factory('System', 'java.lang');
8
11
  exports.unsupportedOperationException = reference_1.ktReference.factory('UnsupportedOperationException', 'java.lang');
9
- // java.io
10
- exports.ioException = reference_1.ktReference.factory('IOException', 'java.io');
11
12
  // java.time
12
13
  exports.offsetDateTime = reference_1.ktReference.factory('OffsetDateTime', 'java.time');
13
14
  // java.util
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.flux = void 0;
3
+ exports.mono = exports.flux = void 0;
4
4
  const reference_1 = require("../nodes/reference");
5
5
  // reactor.core.publisher
6
6
  exports.flux = reference_1.ktReference.genericFactory('Flux', 'reactor.core.publisher');
7
+ exports.mono = reference_1.ktReference.genericFactory('Mono', 'reactor.core.publisher');
@@ -1,21 +1,24 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.controller = exports.httpStatus = exports.responseEntity = exports.validated = exports.autowired = exports.nativeWebRequest = exports.pathVariable = exports.requestMethod = exports.requestParam = exports.requestBody = exports.requestMapping = void 0;
3
+ exports.nativeWebRequest = exports.requestPart = exports.requestParam = exports.requestMethod = exports.requestMapping = exports.requestBody = exports.pathVariable = exports.validated = exports.controller = exports.filePart = exports.responseEntity = exports.httpStatus = exports.autowired = void 0;
4
4
  const reference_1 = require("../nodes/reference");
5
- // org.springframework.web.bind.annotation
6
- exports.requestMapping = reference_1.ktReference.factory('RequestMapping', 'org.springframework.web.bind.annotation');
7
- exports.requestBody = reference_1.ktReference.factory('RequestBody', 'org.springframework.web.bind.annotation');
8
- exports.requestParam = reference_1.ktReference.factory('RequestParam', 'org.springframework.web.bind.annotation');
9
- exports.requestMethod = reference_1.ktReference.factory('RequestMethod', 'org.springframework.web.bind.annotation');
10
- exports.pathVariable = reference_1.ktReference.factory('PathVariable', 'org.springframework.web.bind.annotation');
11
- // org.springframework.web.context.request
12
- exports.nativeWebRequest = reference_1.ktReference.factory('NativeWebRequest', 'org.springframework.web.context.request');
13
5
  // org.springframework.beans.factory.annotation
14
6
  exports.autowired = reference_1.ktReference.factory('Autowired', 'org.springframework.beans.factory.annotation');
15
- // org.springframework.validation.annotation
16
- exports.validated = reference_1.ktReference.factory('Validated', 'org.springframework.validation.annotation');
17
7
  // org.springframework.http
18
- exports.responseEntity = reference_1.ktReference.genericFactory('ResponseEntity', 'org.springframework.http');
19
8
  exports.httpStatus = reference_1.ktReference.factory('HttpStatus', 'org.springframework.http');
9
+ exports.responseEntity = reference_1.ktReference.genericFactory('ResponseEntity', 'org.springframework.http');
10
+ // org.springframework.http.codec.multipart
11
+ exports.filePart = reference_1.ktReference.factory('FilePart', 'org.springframework.http.codec.multipart');
20
12
  // org.springframework.stereotype
21
13
  exports.controller = reference_1.ktReference.factory('Controller', 'org.springframework.stereotype');
14
+ // org.springframework.validation.annotation
15
+ exports.validated = reference_1.ktReference.factory('Validated', 'org.springframework.validation.annotation');
16
+ // org.springframework.web.bind.annotation
17
+ exports.pathVariable = reference_1.ktReference.factory('PathVariable', 'org.springframework.web.bind.annotation');
18
+ exports.requestBody = reference_1.ktReference.factory('RequestBody', 'org.springframework.web.bind.annotation');
19
+ exports.requestMapping = reference_1.ktReference.factory('RequestMapping', 'org.springframework.web.bind.annotation');
20
+ exports.requestMethod = reference_1.ktReference.factory('RequestMethod', 'org.springframework.web.bind.annotation');
21
+ exports.requestParam = reference_1.ktReference.factory('RequestParam', 'org.springframework.web.bind.annotation');
22
+ exports.requestPart = reference_1.ktReference.factory('RequestPart', 'org.springframework.web.bind.annotation');
23
+ // org.springframework.web.context.request
24
+ exports.nativeWebRequest = reference_1.ktReference.factory('NativeWebRequest', 'org.springframework.web.context.request');
@@ -14,24 +14,6 @@ class DefaultKotlinModelGenerator extends file_generator_1.KotlinFileGenerator {
14
14
  // Do not generate types that are only used for anyOf and/or allOf
15
15
  return { type: ast_1.kt.refs.any({ nullable: true }) };
16
16
  }
17
- if (ctx.schema.id === ctx.schema.name) {
18
- // TODO: Add this to @goast/core
19
- const match = ctx.schema.$src.path.match(/\/components\/responses\/([^/]+)\/content\/.+\/schema/);
20
- if (match) {
21
- ctx.schema.name = match[1].toLowerCase().endsWith('response') ? match[1] : match[1] + 'Response';
22
- }
23
- }
24
- if (ctx.schema.isNameGenerated) {
25
- // TODO: Change this in @goast/core
26
- const match = ctx.schema.$src.path.match(/\/paths\/(?<path>.+)\/(?<method>.+)\/responses\/(?<status>\d+)\//);
27
- if (match && match.groups) {
28
- const { path, method, status } = match.groups;
29
- const endpoint = ctx.data.endpoints.find((e) => e.path === path && e.method === method);
30
- if (endpoint) {
31
- ctx.schema.name = `${endpoint.name}${status}Response`;
32
- }
33
- }
34
- }
35
17
  if (this.shouldGenerateTypeDeclaration(ctx, { schema: ctx.schema })) {
36
18
  const typeName = this.getDeclarationTypeName(ctx, { schema: ctx.schema });
37
19
  const packageName = this.getPackageName(ctx, { schema: ctx.schema });
@@ -187,6 +169,8 @@ class DefaultKotlinModelGenerator extends file_generator_1.KotlinFileGenerator {
187
169
  return schema.enum && schema.enum.length > 0
188
170
  ? ast_1.kt.call([this.getType(ctx, { schema }), (0, core_1.toCasing)(String(schema.default), ctx.config.enumValueNameCasing)])
189
171
  : ast_1.kt.string(String(schema.default));
172
+ case 'array':
173
+ return ast_1.kt.call(ast_1.kt.refs.listOf.infer(), Array.isArray(schema.default) ? schema.default.map((x) => ast_1.kt.toNode(x)) : []);
190
174
  default:
191
175
  return 'null';
192
176
  }
@@ -361,10 +345,17 @@ class DefaultKotlinModelGenerator extends file_generator_1.KotlinFileGenerator {
361
345
  if (schema.kind === 'object' && schema.properties.size === 0 && schema.additionalProperties) {
362
346
  return false;
363
347
  }
348
+ if (schema.kind === 'object' && ctx.config.emptyObjectTypeBehavior === 'use-any' && schema.properties.size === 0) {
349
+ return false;
350
+ }
364
351
  // Dynamically generated schemas do not have its own type declaration
365
352
  if (!ctx.data.schemas.some((x) => x.id === schema.id)) {
366
353
  return false;
367
354
  }
355
+ // multipart schemas should not have its own type declaration
356
+ if (schema.$src.path.endsWith('/requestBody/content/multipart/form-data/schema')) {
357
+ return false;
358
+ }
368
359
  return true;
369
360
  }
370
361
  getDeclarationTypeName(ctx, args) {
@@ -7,6 +7,7 @@ exports.defaultKotlinModelsGeneratorConfig = {
7
7
  packageName: 'com.openapi.generated',
8
8
  packageSuffix: '.model',
9
9
  oneOfBehavior: 'treat-as-any-of',
10
+ emptyObjectTypeBehavior: 'generate-empty-class',
10
11
  addJacksonAnnotations: true,
11
12
  addJakartaValidationAnnotations: true,
12
13
  addSwaggerAnnotations: true,
@@ -90,7 +90,7 @@ class DefaultKotlinOkHttp3Generator extends file_generator_1.KotlinFileGenerator
90
90
  ],
91
91
  parameters: parameters.map((p) => {
92
92
  var _a;
93
- return ast_1.kt.parameter((0, core_1.toCasing)(p.name, ctx.config.parameterNameCasing), this.getTypeUsage(ctx, { schema: p.schema, nullable: !p.required }), {
93
+ return ast_1.kt.parameter((0, core_1.toCasing)(p.name, ctx.config.parameterNameCasing), this.getParameterType(ctx, { endpoint, parameter: p }), {
94
94
  description: p.description,
95
95
  default: !p.required ? ast_1.kt.toNode((_a = p.schema) === null || _a === void 0 ? void 0 : _a.default) : null,
96
96
  });
@@ -148,7 +148,7 @@ class DefaultKotlinOkHttp3Generator extends file_generator_1.KotlinFileGenerator
148
148
  ],
149
149
  parameters: parameters.map((p) => {
150
150
  var _a;
151
- return ast_1.kt.parameter((0, core_1.toCasing)(p.name, ctx.config.parameterNameCasing), this.getTypeUsage(ctx, { schema: p.schema, nullable: !p.required }), {
151
+ return ast_1.kt.parameter((0, core_1.toCasing)(p.name, ctx.config.parameterNameCasing), this.getParameterType(ctx, { endpoint, parameter: p }), {
152
152
  description: p.description,
153
153
  default: !p.required ? ast_1.kt.toNode((_a = p.schema) === null || _a === void 0 ? void 0 : _a.default) : null,
154
154
  });
@@ -160,14 +160,13 @@ class DefaultKotlinOkHttp3Generator extends file_generator_1.KotlinFileGenerator
160
160
  });
161
161
  }
162
162
  getEndpointClientHttpInfoMethodBody(ctx, args) {
163
- var _a;
164
163
  const { endpoint, parameters, responseSchema } = args;
165
164
  return (0, core_1.appendValueGroup)([
166
165
  (0, core_1.builderTemplate) `val localVariableConfig = ${ast_1.kt.call([(0, core_1.toCasing)(endpoint.name, 'camel') + 'RequestConfig'], parameters.map((x) => x.name))}`,
167
166
  (0, core_1.builderTemplate) `return ${ast_1.kt.call([
168
167
  ast_1.kt.reference('request', null, {
169
168
  generics: [
170
- this.getTypeUsage(ctx, { schema: (_a = endpoint.requestBody) === null || _a === void 0 ? void 0 : _a.content[0].schema, fallback: ast_1.kt.refs.unit() }),
169
+ this.getRequestBodyType(ctx, { endpoint }),
171
170
  this.getTypeUsage(ctx, { schema: responseSchema, fallback: ast_1.kt.refs.unit() }),
172
171
  ],
173
172
  }),
@@ -175,33 +174,43 @@ class DefaultKotlinOkHttp3Generator extends file_generator_1.KotlinFileGenerator
175
174
  ], '\n');
176
175
  }
177
176
  getEndpointClientRequestConfigMethod(ctx, args) {
178
- var _a;
179
177
  const { endpoint, parameters } = args;
180
178
  const operationName = (0, core_1.toCasing)(endpoint.name, ctx.config.functionNameCasing);
181
- const requestSchema = (_a = endpoint.requestBody) === null || _a === void 0 ? void 0 : _a.content[0].schema;
182
179
  return ast_1.kt.function((0, core_1.toCasing)(args.endpoint.name, ctx.config.functionNameCasing) + 'RequestConfig', {
183
180
  accessModifier: 'private',
184
181
  doc: ast_1.kt.doc(`To obtain the request config of the operation ${operationName}`),
185
182
  annotations: [endpoint.deprecated ? ast_1.kt.annotation(ast_1.kt.refs.deprecated(), [ast_1.kt.argument(ast_1.kt.string(''))]) : null],
186
183
  parameters: parameters.map((p) => {
187
184
  var _a;
188
- return ast_1.kt.parameter((0, core_1.toCasing)(p.name, ctx.config.parameterNameCasing), this.getTypeUsage(ctx, { schema: p.schema, nullable: !p.required }), {
185
+ return ast_1.kt.parameter((0, core_1.toCasing)(p.name, ctx.config.parameterNameCasing), this.getParameterType(ctx, { endpoint, parameter: p }), {
189
186
  description: p.description,
190
187
  default: !p.required ? ast_1.kt.toNode((_a = p.schema) === null || _a === void 0 ? void 0 : _a.default) : null,
191
188
  });
192
189
  }),
193
- returnType: ctx.refs.requestConfig([this.getTypeUsage(ctx, { schema: requestSchema, fallback: ast_1.kt.refs.unit() })]),
194
- body: this.getEndpointClientRequestConfigMethodBody(ctx, { endpoint }),
190
+ returnType: ctx.refs.requestConfig([this.getRequestBodyType(ctx, { endpoint })]),
191
+ body: this.getEndpointClientRequestConfigMethodBody(ctx, { endpoint, parameters }),
195
192
  });
196
193
  }
197
194
  getEndpointClientRequestConfigMethodBody(ctx, args) {
198
- var _a, _b;
199
- const { endpoint } = args;
200
- const queryParameters = endpoint.parameters.filter((x) => x.target === 'query');
195
+ var _a, _b, _c;
196
+ const { endpoint, parameters } = args;
197
+ const queryParameters = parameters.filter((x) => x.target === 'query');
201
198
  const result = (0, core_1.appendValueGroup)([], '\n');
202
199
  if (endpoint.requestBody) {
203
- const bodyParamName = (0, core_1.toCasing)(this.getRequestBodyParamName(ctx, { endpoint }), ctx.config.parameterNameCasing);
204
- result.values.push(`val localVariableBody = ${bodyParamName}`);
200
+ if (((_a = endpoint.requestBody.content[0]) === null || _a === void 0 ? void 0 : _a.type) === 'multipart/form-data') {
201
+ const partConfigs = parameters
202
+ .filter((x) => x.multipart)
203
+ .map((param) => {
204
+ var _a, _b;
205
+ const paramName = (0, core_1.toCasing)(param.name, ctx.config.parameterNameCasing);
206
+ return (0, core_1.builderTemplate) `"${(_b = (_a = param.multipart) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : ''}" to ${ctx.refs.partConfig.infer()}(body = ${paramName})`;
207
+ });
208
+ result.values.push((0, core_1.builderTemplate) `val localVariableBody = ${ast_1.kt.call(ast_1.kt.refs.mapOf([ast_1.kt.refs.string(), ctx.refs.partConfig(['*'])]), partConfigs)}`);
209
+ }
210
+ else {
211
+ const bodyParamName = (0, core_1.toCasing)(this.getRequestBodyParamName(ctx, { endpoint }), ctx.config.parameterNameCasing);
212
+ result.values.push(`val localVariableBody = ${bodyParamName}`);
213
+ }
205
214
  }
206
215
  result.values.push((0, core_1.builderTemplate) `val localVariableQuery: ${ctx.refs.multiValueMap()} = ${ast_1.kt.call([ast_1.kt.refs.mutableMapOf([ast_1.kt.refs.string(), ast_1.kt.refs.list([ast_1.kt.refs.string()])])], [])}${queryParameters.length === 0
207
216
  ? ''
@@ -220,8 +229,8 @@ class DefaultKotlinOkHttp3Generator extends file_generator_1.KotlinFileGenerator
220
229
  }), '\n')}`}
221
230
  }`}`);
222
231
  result.values.push('val localVariableHeaders: MutableMap<String, String> = mutableMapOf()');
223
- if (((_a = endpoint.requestBody) === null || _a === void 0 ? void 0 : _a.content[0]) !== undefined) {
224
- result.values.push(`localVariableHeaders["Content-Type"] = "${(_b = endpoint.requestBody) === null || _b === void 0 ? void 0 : _b.content[0].type}"`);
232
+ if (((_b = endpoint.requestBody) === null || _b === void 0 ? void 0 : _b.content[0]) !== undefined) {
233
+ result.values.push(`localVariableHeaders["Content-Type"] = "${(_c = endpoint.requestBody) === null || _c === void 0 ? void 0 : _c.content[0].type}"`);
225
234
  }
226
235
  result.values.push((0, core_1.builderTemplate) `return ${ast_1.kt.call([ctx.refs.requestConfig.infer()], [
227
236
  ast_1.kt.argument.named('method', ast_1.kt.call([ctx.refs.requestMethod(), endpoint.method.toUpperCase()])),
@@ -244,6 +253,25 @@ class DefaultKotlinOkHttp3Generator extends file_generator_1.KotlinFileGenerator
244
253
  }),
245
254
  ];
246
255
  }
256
+ getParameterType(ctx, args) {
257
+ var _a;
258
+ const { parameter } = args;
259
+ if ((_a = parameter.multipart) === null || _a === void 0 ? void 0 : _a.isFile) {
260
+ return ast_1.kt.refs.java.file();
261
+ }
262
+ return this.getTypeUsage(ctx, {
263
+ schema: parameter.schema,
264
+ nullable: !parameter.required,
265
+ });
266
+ }
267
+ getRequestBodyType(ctx, args) {
268
+ var _a;
269
+ const { endpoint } = args;
270
+ const content = (_a = endpoint.requestBody) === null || _a === void 0 ? void 0 : _a.content[0];
271
+ return (content === null || content === void 0 ? void 0 : content.type) === 'multipart/form-data'
272
+ ? ast_1.kt.refs.map([ast_1.kt.refs.string(), ctx.refs.partConfig(['*'])])
273
+ : this.getTypeUsage(ctx, { schema: content === null || content === void 0 ? void 0 : content.schema, fallback: ast_1.kt.refs.unit() });
274
+ }
247
275
  getTypeUsage(ctx, args) {
248
276
  const { schema, nullable, fallback } = args;
249
277
  const type = this.getSchemaType(ctx, { schema });
@@ -275,26 +303,43 @@ class DefaultKotlinOkHttp3Generator extends file_generator_1.KotlinFileGenerator
275
303
  return schema && ctx.input.kotlin.models[schema.id].type;
276
304
  }
277
305
  getAllParameters(ctx, args) {
306
+ var _a, _b;
278
307
  const { endpoint } = args;
279
308
  const parameters = endpoint.parameters.filter((parameter) => parameter.target === 'query' || parameter.target === 'path');
280
309
  if (endpoint.requestBody) {
281
- const schema = endpoint.requestBody.content[0].schema;
282
- parameters.push({
283
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
284
- $src: undefined,
285
- $ref: undefined,
286
- id: 'body',
287
- name: this.getRequestBodyParamName(ctx, { endpoint }),
288
- target: 'body',
289
- schema,
290
- required: endpoint.requestBody.required,
291
- description: endpoint.requestBody.description,
292
- allowEmptyValue: undefined,
293
- allowReserved: undefined,
294
- deprecated: false,
295
- explode: undefined,
296
- style: undefined,
297
- });
310
+ const content = endpoint.requestBody.content[0];
311
+ let schema = content.schema;
312
+ if (content.type === 'multipart/form-data') {
313
+ if (schema && schema.kind === 'object') {
314
+ schema = (_a = (0, core_1.resolveAnyOfAndAllOf)(schema, true)) !== null && _a !== void 0 ? _a : schema;
315
+ const properties = (_b = schema.properties) !== null && _b !== void 0 ? _b : {};
316
+ for (const [name, property] of properties.entries()) {
317
+ parameters.push(Object.assign(this.createApiParameter({
318
+ id: `multipart-${name}`,
319
+ name,
320
+ target: 'body',
321
+ schema: property.schema,
322
+ required: schema.required.has(name),
323
+ description: property.schema.description,
324
+ }), {
325
+ multipart: {
326
+ name,
327
+ isFile: property.schema.kind === 'string' && property.schema.format === 'binary',
328
+ },
329
+ }));
330
+ }
331
+ }
332
+ }
333
+ else {
334
+ parameters.push(this.createApiParameter({
335
+ id: 'body',
336
+ name: this.getRequestBodyParamName(ctx, { endpoint }),
337
+ target: 'body',
338
+ schema,
339
+ required: endpoint.requestBody.required,
340
+ description: endpoint.requestBody.description,
341
+ }));
342
+ }
298
343
  }
299
344
  return parameters.sort((a, b) => (a.required === b.required ? 0 : a.required ? -1 : 1));
300
345
  }
@@ -320,5 +365,21 @@ class DefaultKotlinOkHttp3Generator extends file_generator_1.KotlinFileGenerator
320
365
  getApiClientName(ctx, args) {
321
366
  return (0, core_1.toCasing)(ctx.service.name, ctx.config.typeNameCasing) + 'ApiClient';
322
367
  }
368
+ createApiParameter(data) {
369
+ return {
370
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
371
+ $src: undefined,
372
+ $ref: undefined,
373
+ schema: undefined,
374
+ required: false,
375
+ description: undefined,
376
+ allowEmptyValue: undefined,
377
+ allowReserved: undefined,
378
+ deprecated: false,
379
+ explode: undefined,
380
+ style: undefined,
381
+ ...data,
382
+ };
383
+ }
323
384
  }
324
385
  exports.DefaultKotlinOkHttp3Generator = DefaultKotlinOkHttp3Generator;
@@ -107,6 +107,7 @@ class DefaultKotlinSpringControllerGenerator extends file_generator_1.KotlinFile
107
107
  const result = ast_1.kt.parameter((0, core_1.toCasing)(parameter.name, ctx.config.parameterNameCasing), this.getParameterType(ctx, { endpoint, parameter }), {});
108
108
  if (ctx.config.addSwaggerAnnotations) {
109
109
  const annotation = ast_1.kt.annotation(ast_1.kt.refs.swagger.parameter(), [
110
+ parameter.multipart ? ast_1.kt.argument.named('name', ast_1.kt.string(parameter.multipart.name)) : null,
110
111
  parameter.description ? ast_1.kt.argument.named('description', ast_1.kt.string((_a = parameter.description) === null || _a === void 0 ? void 0 : _a.trim())) : null,
111
112
  ast_1.kt.argument.named('required', parameter.required),
112
113
  ]);
@@ -119,7 +120,7 @@ class DefaultKotlinSpringControllerGenerator extends file_generator_1.KotlinFile
119
120
  if (!isCorePackage && ctx.config.addJakartaValidationAnnotations) {
120
121
  result.annotations.push(ast_1.kt.annotation(ast_1.kt.refs.jakarta.valid()));
121
122
  }
122
- if (parameter.target === 'body') {
123
+ if (parameter.target === 'body' && !parameter.multipart) {
123
124
  result.annotations.push(ast_1.kt.annotation(ast_1.kt.refs.spring.requestBody()));
124
125
  }
125
126
  if (parameter.target === 'query') {
@@ -135,6 +136,12 @@ class DefaultKotlinSpringControllerGenerator extends file_generator_1.KotlinFile
135
136
  if (parameter.target === 'path') {
136
137
  result.annotations.push(ast_1.kt.annotation(ast_1.kt.refs.spring.pathVariable(), [ast_1.kt.string(parameter.name)]));
137
138
  }
139
+ if (parameter.multipart) {
140
+ result.annotations.push(ast_1.kt.annotation(ast_1.kt.refs.spring.requestPart(), [
141
+ ast_1.kt.argument.named('value', ast_1.kt.string(parameter.multipart.name)),
142
+ ast_1.kt.argument.named('required', parameter.required),
143
+ ]));
144
+ }
138
145
  return result;
139
146
  }
140
147
  getApiInterfaceEndpointMethodBody(ctx, endpoint, parameters) {
@@ -259,11 +266,14 @@ class DefaultKotlinSpringControllerGenerator extends file_generator_1.KotlinFile
259
266
  }
260
267
  // #endregion
261
268
  getParameterType(ctx, args) {
262
- var _a;
269
+ var _a, _b;
263
270
  const { parameter } = args;
271
+ if ((_a = parameter.multipart) === null || _a === void 0 ? void 0 : _a.isFile) {
272
+ return ast_1.kt.refs.reactor.mono([ast_1.kt.refs.spring.filePart()]);
273
+ }
264
274
  const type = this.getTypeUsage(ctx, {
265
275
  schema: parameter.schema,
266
- nullable: (!parameter.required && ((_a = parameter.schema) === null || _a === void 0 ? void 0 : _a.default) === undefined) || undefined,
276
+ nullable: (!parameter.required && ((_b = parameter.schema) === null || _b === void 0 ? void 0 : _b.default) === undefined) || undefined,
267
277
  });
268
278
  return parameter.target === 'body' ? listToFlux(type) : type;
269
279
  }
@@ -330,33 +340,66 @@ class DefaultKotlinSpringControllerGenerator extends file_generator_1.KotlinFile
330
340
  return (0, core_1.toCasing)(ctx.service.name + '_ApiDelegate', ctx.config.typeNameCasing);
331
341
  }
332
342
  getAllParameters(ctx, args) {
343
+ var _a, _b;
333
344
  const { endpoint } = args;
334
345
  const parameters = endpoint.parameters.filter((parameter) => parameter.target === 'query' || parameter.target === 'path');
335
346
  if (endpoint.requestBody) {
336
- const schema = endpoint.requestBody.content[0].schema;
337
- const schemaType = this.getSchemaType(ctx, { schema });
338
- const name = !schemaType || /^Any\??$/.test(schemaType.name)
339
- ? 'body'
340
- : core_1.SourceBuilder.build((b) => ast_1.kt.reference.write(b, schemaType));
341
- parameters.push({
342
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
343
- $src: undefined,
344
- $ref: undefined,
345
- id: 'body',
346
- name,
347
- target: 'body',
348
- schema,
349
- required: endpoint.requestBody.required,
350
- description: endpoint.requestBody.description,
351
- allowEmptyValue: undefined,
352
- allowReserved: undefined,
353
- deprecated: false,
354
- explode: undefined,
355
- style: undefined,
356
- });
347
+ const content = endpoint.requestBody.content[0];
348
+ let schema = content.schema;
349
+ if (content.type === 'multipart/form-data') {
350
+ if (schema && schema.kind === 'object') {
351
+ schema = (_a = (0, core_1.resolveAnyOfAndAllOf)(schema, true)) !== null && _a !== void 0 ? _a : schema;
352
+ const properties = (_b = schema.properties) !== null && _b !== void 0 ? _b : {};
353
+ for (const [name, property] of properties.entries()) {
354
+ parameters.push(Object.assign(this.createApiParameter({
355
+ id: `multipart-${name}`,
356
+ name,
357
+ target: 'body',
358
+ schema: property.schema,
359
+ required: schema.required.has(name),
360
+ description: property.schema.description,
361
+ }), {
362
+ multipart: {
363
+ name,
364
+ isFile: property.schema.kind === 'string' && property.schema.format === 'binary',
365
+ },
366
+ }));
367
+ }
368
+ }
369
+ }
370
+ else {
371
+ const schemaType = this.getSchemaType(ctx, { schema });
372
+ const name = !schemaType || /^Any\??$/.test(schemaType.name)
373
+ ? 'body'
374
+ : core_1.SourceBuilder.build((b) => ast_1.kt.reference.write(b, schemaType));
375
+ parameters.push(this.createApiParameter({
376
+ id: 'body',
377
+ name,
378
+ target: 'body',
379
+ schema,
380
+ required: endpoint.requestBody.required,
381
+ description: endpoint.requestBody.description,
382
+ }));
383
+ }
357
384
  }
358
385
  return parameters;
359
386
  }
387
+ createApiParameter(data) {
388
+ return {
389
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
390
+ $src: undefined,
391
+ $ref: undefined,
392
+ schema: undefined,
393
+ required: false,
394
+ description: undefined,
395
+ allowEmptyValue: undefined,
396
+ allowReserved: undefined,
397
+ deprecated: false,
398
+ explode: undefined,
399
+ style: undefined,
400
+ ...data,
401
+ };
402
+ }
360
403
  }
361
404
  exports.DefaultKotlinSpringControllerGenerator = DefaultKotlinSpringControllerGenerator;
362
405
  function listToFlux(type) {
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/esm/index.js CHANGED
@@ -1,7 +1,8 @@
1
+ export * from './lib/ast';
1
2
  export * from './lib/common-results';
2
3
  export * from './lib/config';
3
- export * from './lib/generators';
4
4
  export * from './lib/file-builder';
5
+ export * from './lib/generators';
5
6
  export * from './lib/import-collection';
7
+ export * from './lib/types';
6
8
  export * from './lib/utils';
7
- export * from './lib/ast';
@@ -1,10 +1,11 @@
1
1
  import { ktReference } from '../nodes/reference';
2
+ // java.io
3
+ export const file = ktReference.factory('File', 'java.io');
4
+ export const ioException = ktReference.factory('IOException', 'java.io');
2
5
  // java.lang
3
- export const system = ktReference.factory('System', 'java.lang');
4
6
  export const illegalStateException = ktReference.factory('IllegalStateException', 'java.lang');
7
+ export const system = ktReference.factory('System', 'java.lang');
5
8
  export const unsupportedOperationException = ktReference.factory('UnsupportedOperationException', 'java.lang');
6
- // java.io
7
- export const ioException = ktReference.factory('IOException', 'java.io');
8
9
  // java.time
9
10
  export const offsetDateTime = ktReference.factory('OffsetDateTime', 'java.time');
10
11
  // java.util
@@ -1,3 +1,4 @@
1
1
  import { ktReference } from '../nodes/reference';
2
2
  // reactor.core.publisher
3
3
  export const flux = ktReference.genericFactory('Flux', 'reactor.core.publisher');
4
+ export const mono = ktReference.genericFactory('Mono', 'reactor.core.publisher');
@@ -1,18 +1,21 @@
1
1
  import { ktReference } from '../nodes/reference';
2
- // org.springframework.web.bind.annotation
3
- export const requestMapping = ktReference.factory('RequestMapping', 'org.springframework.web.bind.annotation');
4
- export const requestBody = ktReference.factory('RequestBody', 'org.springframework.web.bind.annotation');
5
- export const requestParam = ktReference.factory('RequestParam', 'org.springframework.web.bind.annotation');
6
- export const requestMethod = ktReference.factory('RequestMethod', 'org.springframework.web.bind.annotation');
7
- export const pathVariable = ktReference.factory('PathVariable', 'org.springframework.web.bind.annotation');
8
- // org.springframework.web.context.request
9
- export const nativeWebRequest = ktReference.factory('NativeWebRequest', 'org.springframework.web.context.request');
10
2
  // org.springframework.beans.factory.annotation
11
3
  export const autowired = ktReference.factory('Autowired', 'org.springframework.beans.factory.annotation');
12
- // org.springframework.validation.annotation
13
- export const validated = ktReference.factory('Validated', 'org.springframework.validation.annotation');
14
4
  // org.springframework.http
15
- export const responseEntity = ktReference.genericFactory('ResponseEntity', 'org.springframework.http');
16
5
  export const httpStatus = ktReference.factory('HttpStatus', 'org.springframework.http');
6
+ export const responseEntity = ktReference.genericFactory('ResponseEntity', 'org.springframework.http');
7
+ // org.springframework.http.codec.multipart
8
+ export const filePart = ktReference.factory('FilePart', 'org.springframework.http.codec.multipart');
17
9
  // org.springframework.stereotype
18
10
  export const controller = ktReference.factory('Controller', 'org.springframework.stereotype');
11
+ // org.springframework.validation.annotation
12
+ export const validated = ktReference.factory('Validated', 'org.springframework.validation.annotation');
13
+ // org.springframework.web.bind.annotation
14
+ export const pathVariable = ktReference.factory('PathVariable', 'org.springframework.web.bind.annotation');
15
+ export const requestBody = ktReference.factory('RequestBody', 'org.springframework.web.bind.annotation');
16
+ export const requestMapping = ktReference.factory('RequestMapping', 'org.springframework.web.bind.annotation');
17
+ export const requestMethod = ktReference.factory('RequestMethod', 'org.springframework.web.bind.annotation');
18
+ export const requestParam = ktReference.factory('RequestParam', 'org.springframework.web.bind.annotation');
19
+ export const requestPart = ktReference.factory('RequestPart', 'org.springframework.web.bind.annotation');
20
+ // org.springframework.web.context.request
21
+ export const nativeWebRequest = ktReference.factory('NativeWebRequest', 'org.springframework.web.context.request');
@@ -11,24 +11,6 @@ export class DefaultKotlinModelGenerator extends KotlinFileGenerator {
11
11
  // Do not generate types that are only used for anyOf and/or allOf
12
12
  return { type: kt.refs.any({ nullable: true }) };
13
13
  }
14
- if (ctx.schema.id === ctx.schema.name) {
15
- // TODO: Add this to @goast/core
16
- const match = ctx.schema.$src.path.match(/\/components\/responses\/([^/]+)\/content\/.+\/schema/);
17
- if (match) {
18
- ctx.schema.name = match[1].toLowerCase().endsWith('response') ? match[1] : match[1] + 'Response';
19
- }
20
- }
21
- if (ctx.schema.isNameGenerated) {
22
- // TODO: Change this in @goast/core
23
- const match = ctx.schema.$src.path.match(/\/paths\/(?<path>.+)\/(?<method>.+)\/responses\/(?<status>\d+)\//);
24
- if (match && match.groups) {
25
- const { path, method, status } = match.groups;
26
- const endpoint = ctx.data.endpoints.find((e) => e.path === path && e.method === method);
27
- if (endpoint) {
28
- ctx.schema.name = `${endpoint.name}${status}Response`;
29
- }
30
- }
31
- }
32
14
  if (this.shouldGenerateTypeDeclaration(ctx, { schema: ctx.schema })) {
33
15
  const typeName = this.getDeclarationTypeName(ctx, { schema: ctx.schema });
34
16
  const packageName = this.getPackageName(ctx, { schema: ctx.schema });
@@ -184,6 +166,8 @@ export class DefaultKotlinModelGenerator extends KotlinFileGenerator {
184
166
  return schema.enum && schema.enum.length > 0
185
167
  ? kt.call([this.getType(ctx, { schema }), toCasing(String(schema.default), ctx.config.enumValueNameCasing)])
186
168
  : kt.string(String(schema.default));
169
+ case 'array':
170
+ return kt.call(kt.refs.listOf.infer(), Array.isArray(schema.default) ? schema.default.map((x) => kt.toNode(x)) : []);
187
171
  default:
188
172
  return 'null';
189
173
  }
@@ -358,10 +342,17 @@ export class DefaultKotlinModelGenerator extends KotlinFileGenerator {
358
342
  if (schema.kind === 'object' && schema.properties.size === 0 && schema.additionalProperties) {
359
343
  return false;
360
344
  }
345
+ if (schema.kind === 'object' && ctx.config.emptyObjectTypeBehavior === 'use-any' && schema.properties.size === 0) {
346
+ return false;
347
+ }
361
348
  // Dynamically generated schemas do not have its own type declaration
362
349
  if (!ctx.data.schemas.some((x) => x.id === schema.id)) {
363
350
  return false;
364
351
  }
352
+ // multipart schemas should not have its own type declaration
353
+ if (schema.$src.path.endsWith('/requestBody/content/multipart/form-data/schema')) {
354
+ return false;
355
+ }
365
356
  return true;
366
357
  }
367
358
  getDeclarationTypeName(ctx, args) {
@@ -4,6 +4,7 @@ export const defaultKotlinModelsGeneratorConfig = {
4
4
  packageName: 'com.openapi.generated',
5
5
  packageSuffix: '.model',
6
6
  oneOfBehavior: 'treat-as-any-of',
7
+ emptyObjectTypeBehavior: 'generate-empty-class',
7
8
  addJacksonAnnotations: true,
8
9
  addJakartaValidationAnnotations: true,
9
10
  addSwaggerAnnotations: true,