Skip to content

Commit 3884da8

Browse files
authored
Merge pull request #32 from nicolas-chaulet/refactor/use-options-types
refactor(types): generate types for services when useOptions is true
2 parents 3083f66 + 638285a commit 3884da8

38 files changed

+389
-236
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ $ openapi --help
4949
-o, --output <value> Output directory (required)
5050
-c, --client <value> HTTP client to generate [fetch, xhr, node, axios, angular] (default: "fetch")
5151
--name <value> Custom client class name
52-
--useOptions Use options instead of arguments
52+
--useOptions <value> Use options instead of arguments (default: false)
5353
--useUnionTypes Use union types instead of enums
5454
--exportCore <value> Write core files to disk (default: true)
5555
--exportServices <value> Write services to disk [true, false, regexp] (default: true)

bin/index.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ const params = program
1414
.requiredOption('-o, --output <value>', 'Output directory (required)')
1515
.option('-c, --client <value>', 'HTTP client to generate [fetch, xhr, node, axios, angular]', 'fetch')
1616
.option('--name <value>', 'Custom client class name')
17-
.option('--useOptions', 'Use options instead of arguments')
17+
.option('--useOptions [value]', 'Use options instead of arguments', false)
1818
.option('--useUnionTypes', 'Use union types instead of enums')
1919
.option('--autoformat', 'Process generated files with autoformatter', false)
2020
.option('--exportCore <value>', 'Write core files to disk', true)
@@ -57,7 +57,7 @@ if (OpenAPI) {
5757
request: params.request,
5858
useDateType: JSON.parse(params.useDateType) === true,
5959
useOperationId: JSON.parse(params.useOperationId) === true,
60-
useOptions: params.useOptions,
60+
useOptions: JSON.parse(params.useOptions) === true,
6161
useUnionTypes: params.useUnionTypes,
6262
})
6363
.then(() => {

rollup.config.mjs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,9 @@ const handlebarsPlugin = () => ({
3838
escapeEnumName: true,
3939
escapeNewline: true,
4040
ifdef: true,
41+
ifOperationDataOptional: true,
4142
intersection: true,
43+
nameOperationDataType: true,
4244
notEquals: true,
4345
union: true,
4446
useDateType: true,

src/client/interfaces/Operation.d.ts

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,21 @@ import type { OperationParameters } from './OperationParameters';
33
import type { OperationResponse } from './OperationResponse';
44

55
export interface Operation extends OperationParameters {
6-
service: string;
7-
name: string;
8-
summary: string | null;
9-
description: string | null;
106
deprecated: boolean;
7+
description: string | null;
8+
errors: OperationError[];
119
method: string;
10+
/**
11+
* Method name. Methods contain the request logic.
12+
*/
13+
name: string;
1214
path: string;
13-
errors: OperationError[];
14-
results: OperationResponse[];
1515
responseHeader: string | null;
16+
results: OperationResponse[];
17+
/**
18+
* Service name, might be without postfix. This will be used to name the
19+
* exported class.
20+
*/
21+
service: string;
22+
summary: string | null;
1623
}

src/client/interfaces/OperationParameters.d.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@ import type { OperationParameter } from './OperationParameter';
33
export interface OperationParameters {
44
imports: string[];
55
parameters: OperationParameter[];
6-
parametersPath: OperationParameter[];
7-
parametersQuery: OperationParameter[];
8-
parametersForm: OperationParameter[];
6+
parametersBody: OperationParameter | null;
97
parametersCookie: OperationParameter[];
8+
parametersForm: OperationParameter[];
109
parametersHeader: OperationParameter[];
11-
parametersBody: OperationParameter | null;
10+
parametersPath: OperationParameter[];
11+
parametersQuery: OperationParameter[];
1212
}

src/client/interfaces/Options.d.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import { HttpClient } from '../../HttpClient';
2+
import { Indent } from '../interfaces/Indent';
3+
14
export interface Options {
25
autoformat?: boolean;
36
clientName?: string;

src/client/interfaces/Service.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type { Operation } from './Operation';
22

33
export interface Service {
4+
imports: string[];
45
name: string;
56
operations: Operation[];
6-
imports: string[];
77
}

src/openApi/v3/parser/getContent.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { isDefined } from '../../../utils/isDefined';
21
import type { Dictionary } from '../../../utils/types';
32
import type { OpenApi } from '../interfaces/OpenApi';
43
import type { OpenApiMediaType } from '../interfaces/OpenApiMediaType';
@@ -27,15 +26,15 @@ export const getContent = (openApi: OpenApi, content: Dictionary<OpenApiMediaTyp
2726
const cleanMediaType = mediaType.split(';')[0].trim();
2827
return BASIC_MEDIA_TYPES.includes(cleanMediaType);
2928
})
30-
.find(mediaType => isDefined(content[mediaType]?.schema));
29+
.find(mediaType => Boolean(content[mediaType]?.schema));
3130
if (basicMediaTypeWithSchema) {
3231
return {
3332
mediaType: basicMediaTypeWithSchema,
3433
schema: content[basicMediaTypeWithSchema].schema as OpenApiSchema,
3534
};
3635
}
3736

38-
const firstMediaTypeWithSchema = Object.keys(content).find(mediaType => isDefined(content[mediaType]?.schema));
37+
const firstMediaTypeWithSchema = Object.keys(content).find(mediaType => Boolean(content[mediaType]?.schema));
3938
if (firstMediaTypeWithSchema) {
4039
return {
4140
mediaType: firstMediaTypeWithSchema,

src/openApi/v3/parser/getOperation.ts

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -24,42 +24,42 @@ export const getOperation = (
2424
pathParams: OperationParameters,
2525
options: Options
2626
): Operation => {
27-
const serviceName = getServiceName(tag);
28-
const operationName = getOperationName(url, method, options, op.operationId);
27+
const service = getServiceName(tag);
28+
const name = getOperationName(url, method, options, op.operationId);
2929

3030
// Create a new operation object for this method.
3131
const operation: Operation = {
32-
service: serviceName,
33-
name: operationName,
34-
summary: op.summary || null,
32+
deprecated: Boolean(op.deprecated),
3533
description: op.description || null,
36-
deprecated: op.deprecated === true,
34+
errors: [],
35+
imports: [],
3736
method: method.toUpperCase(),
38-
path: url,
37+
name,
3938
parameters: [...pathParams.parameters],
40-
parametersPath: [...pathParams.parametersPath],
41-
parametersQuery: [...pathParams.parametersQuery],
39+
parametersBody: pathParams.parametersBody,
40+
parametersCookie: [...pathParams.parametersCookie],
4241
parametersForm: [...pathParams.parametersForm],
4342
parametersHeader: [...pathParams.parametersHeader],
44-
parametersCookie: [...pathParams.parametersCookie],
45-
parametersBody: pathParams.parametersBody,
46-
imports: [],
47-
errors: [],
48-
results: [],
43+
parametersPath: [...pathParams.parametersPath],
44+
parametersQuery: [...pathParams.parametersQuery],
45+
path: url,
4946
responseHeader: null,
47+
results: [],
48+
service,
49+
summary: op.summary || null,
5050
};
5151

5252
// Parse the operation parameters (path, query, body, etc).
5353
if (op.parameters) {
5454
const parameters = getOperationParameters(openApi, op.parameters);
5555
operation.imports.push(...parameters.imports);
5656
operation.parameters.push(...parameters.parameters);
57-
operation.parametersPath.push(...parameters.parametersPath);
58-
operation.parametersQuery.push(...parameters.parametersQuery);
57+
operation.parametersBody = parameters.parametersBody;
58+
operation.parametersCookie.push(...parameters.parametersCookie);
5959
operation.parametersForm.push(...parameters.parametersForm);
6060
operation.parametersHeader.push(...parameters.parametersHeader);
61-
operation.parametersCookie.push(...parameters.parametersCookie);
62-
operation.parametersBody = parameters.parametersBody;
61+
operation.parametersPath.push(...parameters.parametersPath);
62+
operation.parametersQuery.push(...parameters.parametersQuery);
6363
}
6464

6565
if (op.requestBody) {
@@ -78,8 +78,8 @@ export const getOperation = (
7878
operation.responseHeader = getOperationResponseHeader(operationResults);
7979

8080
operationResults.forEach(operationResult => {
81-
operation.results.push(operationResult);
8281
operation.imports.push(...operationResult.imports);
82+
operation.results.push(operationResult);
8383
});
8484
}
8585

src/openApi/v3/parser/getServices.ts

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,17 @@
1+
import type { Operation } from '../../../client/interfaces/Operation';
12
import type { Options } from '../../../client/interfaces/Options';
23
import type { Service } from '../../../client/interfaces/Service';
34
import { unique } from '../../../utils/unique';
45
import type { OpenApi } from '../interfaces/OpenApi';
56
import { getOperation } from './getOperation';
67
import { getOperationParameters } from './getOperationParameters';
78

9+
const getNewService = (operation: Operation): Service => ({
10+
imports: [],
11+
name: operation.service,
12+
operations: [],
13+
});
14+
815
/**
916
* Get the OpenAPI services
1017
*/
@@ -20,30 +27,21 @@ export const getServices = (openApi: OpenApi, options: Options): Service[] => {
2027
for (const method in path) {
2128
if (path.hasOwnProperty(method)) {
2229
switch (method) {
23-
case 'get':
24-
case 'put':
25-
case 'post':
2630
case 'delete':
27-
case 'options':
31+
case 'get':
2832
case 'head':
33+
case 'options':
2934
case 'patch':
35+
case 'post':
36+
case 'put':
3037
// Each method contains an OpenAPI operation, we parse the operation
3138
const op = path[method]!;
3239
const tags = op.tags?.length ? op.tags.filter(unique) : ['Default'];
3340
tags.forEach(tag => {
3441
const operation = getOperation(openApi, url, method, tag, op, pathParams, options);
35-
36-
// If we have already declared a service, then we should fetch that and
37-
// append the new method to it. Otherwise we should create a new service object.
38-
const service: Service = services.get(operation.service) || {
39-
name: operation.service,
40-
operations: [],
41-
imports: [],
42-
};
43-
44-
// Push the operation in the service
45-
service.operations.push(operation);
46-
service.imports.push(...operation.imports);
42+
const service = services.get(operation.service) || getNewService(operation);
43+
service.imports = [...service.imports, ...operation.imports];
44+
service.operations = [...service.operations, operation];
4745
services.set(operation.service, service);
4846
});
4947
break;

0 commit comments

Comments
 (0)