Skip to content

Commit e19f361

Browse files
committed
Merge remote-tracking branch 'upstream/master'
2 parents 84c7ec3 + ac8e744 commit e19f361

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

74 files changed

+752
-667
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ The OpenAPI spec allows you to define [enums](https://swagger.io/docs/specificat
130130
data model. By default, we convert these enums definitions to [TypeScript enums](https://www.typescriptlang.org/docs/handbook/enums.html).
131131
However, these enums are merged inside the namespace of the model, this is unsupported by Babel, [see docs](https://babeljs.io/docs/en/babel-plugin-transform-typescript#impartial-namespace-support).
132132
Because we also want to support projects that use Babel [@babel/plugin-transform-typescript](https://babeljs.io/docs/en/babel-plugin-transform-typescript),
133-
we offer the flag `--useOptions` to generate [union types](https://www.typescriptlang.org/docs/handbook/unions-and-intersections.html#union-types)
133+
we offer the flag `--useUnionTypes` to generate [union types](https://www.typescriptlang.org/docs/handbook/unions-and-intersections.html#union-types)
134134
instead of the traditional enums. The difference can be seen below:
135135

136136
**Enums:**

bin/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ program
1919
.option('--exportServices <value>', 'Write services to disk', true)
2020
.option('--exportModels <value>', 'Write models to disk', true)
2121
.option('--exportSchemas <value>', 'Write schemas to disk', false)
22+
.option('--request <value>', 'Path to custom request file')
2223
.parse(process.argv);
2324

2425
const OpenAPI = require(path.resolve(__dirname, '../dist/index.js'));
@@ -34,6 +35,7 @@ if (OpenAPI) {
3435
exportServices: JSON.parse(program.exportServices) === true,
3536
exportModels: JSON.parse(program.exportModels) === true,
3637
exportSchemas: JSON.parse(program.exportSchemas) === true,
38+
request: program.request,
3739
})
3840
.then(() => {
3941
process.exit(0);

jest.config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ module.exports = {
99
'<rootDir>/src/**/*.spec.ts',
1010
'<rootDir>/test/index.spec.js',
1111
],
12+
moduleFileExtensions: ['js', 'ts', 'd.ts'],
1213
moduleNameMapper: {
1314
'\\.hbs$': '<rootDir>/src/templates/__mocks__/index.js',
1415
},

package.json

Lines changed: 26 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "openapi-typescript-codegen",
3-
"version": "0.7.0-beta-3",
3+
"version": "0.7.2",
44
"description": "Library that generates Typescript clients based on the OpenAPI specification.",
55
"author": "Ferdi Koomen",
66
"homepage": "https://github.com/ferdikoomen/openapi-typescript-codegen",
@@ -61,44 +61,45 @@
6161
"codecov": "codecov --token=66c30c23-8954-4892-bef9-fbaed0a2e42b"
6262
},
6363
"dependencies": {
64-
"camelcase": "6.2.0",
65-
"commander": "6.2.0",
66-
"handlebars": "4.7.6",
67-
"js-yaml": "3.14.0",
68-
"mkdirp": "1.0.4",
69-
"path": "0.12.7",
70-
"rimraf": "3.0.2"
64+
"camelcase": "^6.2.0",
65+
"commander": "^6.2.0",
66+
"handlebars": "^4.7.6",
67+
"js-yaml": "^3.14.0",
68+
"mkdirp": "^1.0.4",
69+
"rimraf": "^3.0.2"
7170
},
7271
"devDependencies": {
73-
"@babel/cli": "7.12.7",
74-
"@babel/core": "7.12.3",
75-
"@babel/preset-env": "7.12.1",
72+
"@babel/cli": "7.12.10",
73+
"@babel/core": "7.12.10",
74+
"@babel/preset-env": "7.12.11",
7675
"@babel/preset-typescript": "7.12.7",
77-
"@rollup/plugin-commonjs": "16.0.0",
78-
"@rollup/plugin-node-resolve": "10.0.0",
76+
"@rollup/plugin-commonjs": "17.0.0",
77+
"@rollup/plugin-node-resolve": "11.0.1",
7978
"@types/express": "4.17.9",
80-
"@types/jest": "26.0.15",
79+
"@types/jest": "26.0.19",
8180
"@types/js-yaml": "3.12.5",
82-
"@types/node": "14.14.9",
81+
"@types/node": "14.14.19",
8382
"@types/node-fetch": "2.5.7",
84-
"@typescript-eslint/eslint-plugin": "4.8.1",
85-
"@typescript-eslint/parser": "4.8.1",
83+
"@types/qs": "6.9.5",
84+
"@typescript-eslint/eslint-plugin": "4.11.1",
85+
"@typescript-eslint/parser": "4.11.1",
8686
"codecov": "3.8.1",
87-
"eslint": "7.14.0",
88-
"eslint-config-prettier": "6.15.0",
89-
"eslint-plugin-prettier": "3.1.4",
90-
"eslint-plugin-simple-import-sort": "6.0.1",
87+
"eslint": "7.17.0",
88+
"eslint-config-prettier": "7.1.0",
89+
"eslint-plugin-prettier": "3.3.0",
90+
"eslint-plugin-simple-import-sort": "7.0.0",
9191
"express": "4.17.1",
9292
"form-data": "3.0.0",
9393
"glob": "7.1.6",
9494
"jest": "26.6.3",
9595
"jest-cli": "26.6.3",
9696
"node-fetch": "2.6.1",
97-
"prettier": "2.2.0",
98-
"puppeteer": "5.4.1",
99-
"rollup": "2.33.3",
97+
"prettier": "2.2.1",
98+
"puppeteer": "5.5.0",
99+
"qs": "6.9.4",
100+
"rollup": "2.35.1",
100101
"rollup-plugin-terser": "7.0.2",
101102
"rollup-plugin-typescript2": "0.29.0",
102-
"typescript": "4.0.5"
103+
"typescript": "4.1.3"
103104
}
104105
}

rollup.config.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ const handlebarsPlugin = () => ({
3434
knownHelpers: {
3535
equals: true,
3636
notEquals: true,
37+
containsSpaces: true,
38+
union: true,
3739
},
3840
});
3941
return `export default ${templateSpec};`;
@@ -65,6 +67,7 @@ module.exports = {
6567
'fs',
6668
'os',
6769
'util',
70+
'path',
6871
'http',
6972
'https',
7073
'handlebars/runtime',

src/HttpClient.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export enum HttpClient {
2+
FETCH = 'fetch',
3+
XHR = 'xhr',
4+
NODE = 'node',
5+
}

src/index.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { HttpClient } from './HttpClient';
12
import { parse as parseV2 } from './openApi/v2';
23
import { parse as parseV3 } from './openApi/v3';
34
import { getOpenApiSpec } from './utils/getOpenApiSpec';
@@ -7,11 +8,7 @@ import { postProcessClient } from './utils/postProcessClient';
78
import { registerHandlebarTemplates } from './utils/registerHandlebarTemplates';
89
import { writeClient } from './utils/writeClient';
910

10-
export enum HttpClient {
11-
FETCH = 'fetch',
12-
XHR = 'xhr',
13-
NODE = 'node',
14-
}
11+
export { HttpClient } from './HttpClient';
1512

1613
export type Options = {
1714
input: string | Record<string, any>;
@@ -23,6 +20,7 @@ export type Options = {
2320
exportServices?: boolean;
2421
exportModels?: boolean;
2522
exportSchemas?: boolean;
23+
request?: string;
2624
write?: boolean;
2725
};
2826

@@ -39,6 +37,7 @@ export type Options = {
3937
* @param exportServices: Generate services
4038
* @param exportModels: Generate models
4139
* @param exportSchemas: Generate schemas
40+
* @param request: Path to custom request file
4241
* @param write Write the files to disk (true or false)
4342
*/
4443
export async function generate({
@@ -51,6 +50,7 @@ export async function generate({
5150
exportServices = true,
5251
exportModels = true,
5352
exportSchemas = false,
53+
request,
5454
write = true,
5555
}: Options): Promise<void> {
5656
const openApi = isString(input) ? await getOpenApiSpec(input) : input;
@@ -62,15 +62,15 @@ export async function generate({
6262
const client = parseV2(openApi);
6363
const clientFinal = postProcessClient(client);
6464
if (!write) break;
65-
await writeClient(clientFinal, templates, output, httpClient, useOptions, useUnionTypes, exportCore, exportServices, exportModels, exportSchemas);
65+
await writeClient(clientFinal, templates, output, httpClient, useOptions, useUnionTypes, exportCore, exportServices, exportModels, exportSchemas, request);
6666
break;
6767
}
6868

6969
case OpenApiVersion.V3: {
7070
const client = parseV3(openApi);
7171
const clientFinal = postProcessClient(client);
7272
if (!write) break;
73-
await writeClient(clientFinal, templates, output, httpClient, useOptions, useUnionTypes, exportCore, exportServices, exportModels, exportSchemas);
73+
await writeClient(clientFinal, templates, output, httpClient, useOptions, useUnionTypes, exportCore, exportServices, exportModels, exportSchemas, request);
7474
break;
7575
}
7676
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { escapeDescription } from './escapeDescription';
2+
3+
describe('escapeDescription', () => {
4+
it('should escape', () => {
5+
expect(escapeDescription('foo `test` bar')).toEqual('foo \\`test\\` bar');
6+
});
7+
8+
it('should not escape', () => {
9+
expect(escapeDescription('')).toEqual('');
10+
expect(escapeDescription('fooBar')).toEqual('fooBar');
11+
expect(escapeDescription('foo \\`test\\` bar')).toEqual('foo \\`test\\` bar');
12+
});
13+
});
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export function escapeDescription(value: string): string {
2+
return value.replace(/([^\\])`/g, '$1\\`');
3+
}

src/openApi/v2/parser/getComment.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
import * as os from 'os';
1+
import { EOL } from 'os';
22

33
import { getComment } from './getComment';
44

55
describe('getComment', () => {
66
it('should parse comments', () => {
7-
const multiline = 'Testing multiline comments.' + os.EOL + ' * This must go to the next line.' + os.EOL + ' * ' + os.EOL + ' * This will contain a break.';
7+
const multiline = 'Testing multiline comments.' + EOL + ' * This must go to the next line.' + EOL + ' * ' + EOL + ' * This will contain a break.';
88
expect(getComment('')).toEqual(null);
99
expect(getComment('Hello')).toEqual('Hello');
1010
expect(getComment('Hello World!')).toEqual('Hello World!');

src/openApi/v2/parser/getComment.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import * as os from 'os';
1+
import { EOL } from 'os';
22

33
/**
44
* Cleanup comment and prefix multiline comments with "*",
@@ -7,7 +7,7 @@ import * as os from 'os';
77
*/
88
export function getComment(comment?: string): string | null {
99
if (comment) {
10-
return comment.replace(/\r?\n(.*)/g, (_, w) => `${os.EOL} * ${w.trim()}`);
10+
return comment.replace(/\r?\n(.*)/g, (_, w) => `${EOL} * ${w.trim()}`);
1111
}
1212
return null;
1313
}

src/openApi/v2/parser/getEnum.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { Enum } from '../../../client/interfaces/Enum';
2-
import { isDefined } from './isDefined';
2+
import { isDefined } from '../../../utils/isDefined';
33

44
export function getEnum(values?: (string | number)[]): Enum[] {
55
if (Array.isArray(values)) {

src/openApi/v2/parser/getModel.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type { Model } from '../../../client/interfaces/Model';
2+
import { getPattern } from '../../../utils/getPattern';
23
import type { OpenApi } from '../interfaces/OpenApi';
34
import type { OpenApiSchema } from '../interfaces/OpenApiSchema';
45
import { extendEnum } from './extendEnum';
@@ -7,7 +8,6 @@ import { getEnum } from './getEnum';
78
import { getEnumFromDescription } from './getEnumFromDescription';
89
import { getModelComposition } from './getModelComposition';
910
import { getModelProperties } from './getModelProperties';
10-
import { getPattern } from './getPattern';
1111
import { getType } from './getType';
1212

1313
export function getModel(openApi: OpenApi, definition: OpenApiSchema, isDefinition: boolean = false, name: string = ''): Model {

src/openApi/v2/parser/getModelComposition.ts

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,20 @@ export function getModelComposition(openApi: OpenApi, definitions: OpenApiSchema
1414
properties: [],
1515
};
1616

17-
const modes = definitions.map(definition => getModel(openApi, definition));
18-
modes.forEach(model => {
19-
composition.imports.push(...model.imports);
20-
composition.enums.push(...model.enums);
21-
composition.properties.push(model);
22-
});
17+
const models = definitions.map(definition => getModel(openApi, definition));
18+
models
19+
.filter(model => {
20+
const hasProperties = model.properties.length;
21+
const hasEnums = model.enums.length;
22+
const isObject = model.type === 'any';
23+
const isEmpty = isObject && !hasProperties && !hasEnums;
24+
return !isEmpty;
25+
})
26+
.forEach(model => {
27+
composition.imports.push(...model.imports);
28+
composition.enums.push(...model.enums);
29+
composition.properties.push(model);
30+
});
2331

2432
return composition;
2533
}

src/openApi/v2/parser/getModelProperties.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import type { Model } from '../../../client/interfaces/Model';
2+
import { getPattern } from '../../../utils/getPattern';
23
import type { OpenApi } from '../interfaces/OpenApi';
34
import type { OpenApiSchema } from '../interfaces/OpenApiSchema';
45
import { escapeName } from './escapeName';
56
import { getComment } from './getComment';
67
import type { getModel } from './getModel';
7-
import { getPattern } from './getPattern';
88
import { getType } from './getType';
99

1010
// Fix for circular dependency
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type { OperationError } from '../../../client/interfaces/OperationError';
22
import type { OperationResponse } from '../../../client/interfaces/OperationResponse';
3+
import { escapeDescription } from './escapeDescription';
34

45
export function getOperationErrors(operationResponses: OperationResponse[]): OperationError[] {
56
return operationResponses
@@ -8,6 +9,6 @@ export function getOperationErrors(operationResponses: OperationResponse[]): Ope
89
})
910
.map(response => ({
1011
code: response.code,
11-
description: response.description!,
12+
description: escapeDescription(response.description!),
1213
}));
1314
}

src/openApi/v2/parser/getOperationParameter.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type { OperationParameter } from '../../../client/interfaces/OperationParameter';
2+
import { getPattern } from '../../../utils/getPattern';
23
import type { OpenApi } from '../interfaces/OpenApi';
34
import type { OpenApiParameter } from '../interfaces/OpenApiParameter';
45
import { extendEnum } from './extendEnum';
@@ -8,7 +9,6 @@ import { getEnumFromDescription } from './getEnumFromDescription';
89
import { getModel } from './getModel';
910
import { getOperationParameterDefault } from './getOperationParameterDefault';
1011
import { getOperationParameterName } from './getOperationParameterName';
11-
import { getPattern } from './getPattern';
1212
import { getType } from './getType';
1313

1414
export function getOperationParameter(openApi: OpenApi, parameter: OpenApiParameter): OperationParameter {

src/openApi/v2/parser/getOperationResponse.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import type { OperationResponse } from '../../../client/interfaces/OperationResponse';
2+
import { getPattern } from '../../../utils/getPattern';
23
import type { OpenApi } from '../interfaces/OpenApi';
34
import type { OpenApiResponse } from '../interfaces/OpenApiResponse';
45
import { getComment } from './getComment';
56
import { getModel } from './getModel';
6-
import { getPattern } from './getPattern';
77
import { getType } from './getType';
88

99
export function getOperationResponse(openApi: OpenApi, response: OpenApiResponse, responseCode: number): OperationResponse {
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { escapeDescription } from './escapeDescription';
2+
3+
describe('escapeDescription', () => {
4+
it('should escape', () => {
5+
expect(escapeDescription('foo `test` bar')).toEqual('foo \\`test\\` bar');
6+
});
7+
8+
it('should not escape', () => {
9+
expect(escapeDescription('')).toEqual('');
10+
expect(escapeDescription('fooBar')).toEqual('fooBar');
11+
expect(escapeDescription('foo \\`test\\` bar')).toEqual('foo \\`test\\` bar');
12+
});
13+
});
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export function escapeDescription(value: string): string {
2+
return value.replace(/([^\\])`/g, '$1\\`');
3+
}

src/openApi/v3/parser/getComment.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
import * as os from 'os';
1+
import { EOL } from 'os';
22

33
import { getComment } from './getComment';
44

55
describe('getComment', () => {
66
it('should parse comments', () => {
7-
const multiline = 'Testing multiline comments.' + os.EOL + ' * This must go to the next line.' + os.EOL + ' * ' + os.EOL + ' * This will contain a break.';
7+
const multiline = 'Testing multiline comments.' + EOL + ' * This must go to the next line.' + EOL + ' * ' + EOL + ' * This will contain a break.';
88
expect(getComment('')).toEqual(null);
99
expect(getComment('Hello')).toEqual('Hello');
1010
expect(getComment('Hello World!')).toEqual('Hello World!');

src/openApi/v3/parser/getComment.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import * as os from 'os';
1+
import { EOL } from 'os';
22

33
/**
44
* Cleanup comment and prefix multiline comments with "*",
@@ -7,7 +7,7 @@ import * as os from 'os';
77
*/
88
export function getComment(comment?: string): string | null {
99
if (comment) {
10-
return comment.replace(/\r?\n(.*)/g, (_, w) => `${os.EOL} * ${w.trim()}`);
10+
return comment.replace(/\r?\n(.*)/g, (_, w) => `${EOL} * ${w.trim()}`);
1111
}
1212
return null;
1313
}

src/openApi/v3/parser/getEnum.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { Enum } from '../../../client/interfaces/Enum';
2-
import { isDefined } from './isDefined';
2+
import { isDefined } from '../../../utils/isDefined';
33

44
export function getEnum(values?: (string | number)[]): Enum[] {
55
if (Array.isArray(values)) {

0 commit comments

Comments
 (0)