swagger-typescript-api 9.1.1 → 9.3.1
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.
- package/CHANGELOG.md +14 -0
- package/LICENSE +21 -21
- package/README.md +2 -1
- package/index.d.ts +20 -40
- package/index.js +20 -17
- package/package.json +6 -3
- package/src/config.js +4 -0
- package/src/index.js +43 -4
- package/src/prettierOptions.js +23 -0
- package/src/routes.js +30 -0
- package/src/schema.js +1 -0
- package/src/swagger.js +18 -5
- package/src/typeFormatters.js +2 -2
- package/templates/base/http-clients/axios-http-client.eta +10 -2
- package/templates/base/http-clients/fetch-http-client.eta +11 -1
- package/templates/default/api.eta +5 -1
- package/templates/modular/api.eta +6 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# next release
|
|
2
2
|
|
|
3
|
+
# 9.2.0
|
|
4
|
+
|
|
5
|
+
Features:
|
|
6
|
+
- full response typing for status code, data and headers. (#272, thanks @rustyconover)
|
|
7
|
+
- --unwrap-response-data to unwrap the data item from the response (#268, thanks @laktak)
|
|
8
|
+
|
|
9
|
+
Fixes:
|
|
10
|
+
- fix: formdata in axios template (#277, thanks @tiagoskaneta)
|
|
11
|
+
|
|
12
|
+
# 9.1.2
|
|
13
|
+
|
|
14
|
+
Fixes:
|
|
15
|
+
- Bug with --single-http-client and private `http` property
|
|
16
|
+
|
|
3
17
|
# 9.1.1
|
|
4
18
|
|
|
5
19
|
Fixes:
|
package/LICENSE
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2019-present acacode
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining
|
|
6
|
-
a copy of this software and associated documentation files (the
|
|
7
|
-
'Software'), to deal in the Software without restriction, including
|
|
8
|
-
without limitation the rights to use, copy, modify, merge, publish,
|
|
9
|
-
distribute, sublicense, and/or sell copies of the Software, and to
|
|
10
|
-
permit persons to whom the Software is furnished to do so, subject to
|
|
11
|
-
the following conditions:
|
|
12
|
-
|
|
13
|
-
The above copyright notice and this permission notice shall be
|
|
14
|
-
included in all copies or substantial portions of the Software.
|
|
15
|
-
|
|
16
|
-
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
|
17
|
-
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
18
|
-
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
19
|
-
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
20
|
-
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
21
|
-
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2019-present acacode
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
6
|
+
a copy of this software and associated documentation files (the
|
|
7
|
+
'Software'), to deal in the Software without restriction, including
|
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
11
|
+
the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be
|
|
14
|
+
included in all copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
19
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
20
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
21
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
22
22
|
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
CHANGED
|
@@ -63,6 +63,7 @@ Options:
|
|
|
63
63
|
--default-response <type> default type for empty response schema (default: "void")
|
|
64
64
|
--type-prefix <string> data contract name prefix (default: "")
|
|
65
65
|
--type-suffix <string> data contract name suffix (default: "")
|
|
66
|
+
--patch fix up small errors in the swagger source definition (default: false)
|
|
66
67
|
-h, --help display help for command
|
|
67
68
|
```
|
|
68
69
|
|
|
@@ -99,7 +100,7 @@ generateApi({
|
|
|
99
100
|
toJS: false,
|
|
100
101
|
extractRequestParams: false,
|
|
101
102
|
extractRequestBody: false,
|
|
102
|
-
prettier: {
|
|
103
|
+
prettier: { // By default prettier config is load from your project
|
|
103
104
|
printWidth: 120,
|
|
104
105
|
tabWidth: 2,
|
|
105
106
|
trailingComma: "all",
|
package/index.d.ts
CHANGED
|
@@ -88,6 +88,10 @@ interface GenerateApiParams {
|
|
|
88
88
|
* extract request params to data contract (Also combine path params and query params into one object)
|
|
89
89
|
*/
|
|
90
90
|
extractRequestParams?: boolean;
|
|
91
|
+
/**
|
|
92
|
+
* extract request body type to data contract
|
|
93
|
+
*/
|
|
94
|
+
extractRequestBody?: boolean;
|
|
91
95
|
/**
|
|
92
96
|
* prettier configuration
|
|
93
97
|
*/
|
|
@@ -112,6 +116,11 @@ interface GenerateApiParams {
|
|
|
112
116
|
* extra templates
|
|
113
117
|
*/
|
|
114
118
|
extraTemplates?: { name: string; path: string }[];
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* fix up small errors in the swagger source definition
|
|
122
|
+
*/
|
|
123
|
+
patch?: boolean;
|
|
115
124
|
}
|
|
116
125
|
|
|
117
126
|
export interface Hooks {
|
|
@@ -126,14 +135,9 @@ export interface Hooks {
|
|
|
126
135
|
/** customize configuration object before sending it to ETA templates */
|
|
127
136
|
onPrepareConfig?: <C extends GenerateApiConfiguration>(currentConfiguration: C) => C | void;
|
|
128
137
|
/** customize route name as you need */
|
|
129
|
-
onCreateRouteName?: (
|
|
130
|
-
routeNameInfo: RouteNameInfo,
|
|
131
|
-
rawRouteInfo: RawRouteInfo,
|
|
132
|
-
) => RouteNameInfo | void;
|
|
138
|
+
onCreateRouteName?: (routeNameInfo: RouteNameInfo, rawRouteInfo: RawRouteInfo) => RouteNameInfo | void;
|
|
133
139
|
/** customize request params (path params, query params) */
|
|
134
|
-
onCreateRequestParams?: (
|
|
135
|
-
rawType: SchemaComponent["rawTypeData"],
|
|
136
|
-
) => SchemaComponent["rawTypeData"] | void;
|
|
140
|
+
onCreateRequestParams?: (rawType: SchemaComponent["rawTypeData"]) => SchemaComponent["rawTypeData"] | void;
|
|
137
141
|
/** customize name of model type */
|
|
138
142
|
onFormatTypeName?: (typeName: string, rawTypeName?: string) => string | void;
|
|
139
143
|
/** customize name of route (operationId), you can do it with using onCreateRouteName too */
|
|
@@ -210,14 +214,10 @@ export interface SchemaComponent {
|
|
|
210
214
|
discriminator?: {
|
|
211
215
|
propertyName?: string;
|
|
212
216
|
};
|
|
213
|
-
$parsed: ParsedSchema<
|
|
214
|
-
SchemaTypeObjectContent | SchemaTypeEnumContent | SchemaTypePrimitiveContent
|
|
215
|
-
>;
|
|
217
|
+
$parsed: ParsedSchema<SchemaTypeObjectContent | SchemaTypeEnumContent | SchemaTypePrimitiveContent>;
|
|
216
218
|
};
|
|
217
219
|
componentName: string;
|
|
218
|
-
typeData: ParsedSchema<
|
|
219
|
-
SchemaTypeObjectContent | SchemaTypeEnumContent | SchemaTypePrimitiveContent
|
|
220
|
-
> | null;
|
|
220
|
+
typeData: ParsedSchema<SchemaTypeObjectContent | SchemaTypeEnumContent | SchemaTypePrimitiveContent> | null;
|
|
221
221
|
}
|
|
222
222
|
|
|
223
223
|
export enum RequestContentKind {
|
|
@@ -341,10 +341,7 @@ export interface GenerateApiConfiguration {
|
|
|
341
341
|
formatDescription: (description: string, inline?: boolean) => string;
|
|
342
342
|
internalCase: (value: string) => string;
|
|
343
343
|
classNameCase: (value: string) => string;
|
|
344
|
-
getInlineParseContent: (
|
|
345
|
-
rawTypeData: SchemaComponent["rawTypeData"],
|
|
346
|
-
typeName?: string,
|
|
347
|
-
) => string;
|
|
344
|
+
getInlineParseContent: (rawTypeData: SchemaComponent["rawTypeData"], typeName?: string) => string;
|
|
348
345
|
getParseContent: (rawTypeData: SchemaComponent["rawTypeData"], typeName?: string) => ModelType;
|
|
349
346
|
getComponentByRef: (ref: string) => SchemaComponent;
|
|
350
347
|
parseSchema: (
|
|
@@ -352,14 +349,8 @@ export interface GenerateApiConfiguration {
|
|
|
352
349
|
typeName?: string,
|
|
353
350
|
formattersMap?: Record<MAIN_SCHEMA_TYPES, (content: ModelType) => string>,
|
|
354
351
|
) => ModelType;
|
|
355
|
-
formatters: Record<
|
|
356
|
-
|
|
357
|
-
(content: string | object | string[] | object[]) => string
|
|
358
|
-
>;
|
|
359
|
-
inlineExtraFormatters: Record<
|
|
360
|
-
Exclude<MAIN_SCHEMA_TYPES, SCHEMA_TYPES.PRIMITIVE>,
|
|
361
|
-
(schema: ModelType) => string
|
|
362
|
-
>;
|
|
352
|
+
formatters: Record<MAIN_SCHEMA_TYPES, (content: string | object | string[] | object[]) => string>;
|
|
353
|
+
inlineExtraFormatters: Record<Exclude<MAIN_SCHEMA_TYPES, SCHEMA_TYPES.PRIMITIVE>, (schema: ModelType) => string>;
|
|
363
354
|
formatModelName: (name: string) => string;
|
|
364
355
|
fmtToJSDocLine: (line: string, params?: { eol?: boolean }) => string;
|
|
365
356
|
_: import("lodash").LoDashStatic;
|
|
@@ -370,12 +361,7 @@ export interface GenerateApiConfiguration {
|
|
|
370
361
|
export interface GenerateApiOutput {
|
|
371
362
|
configuration: GenerateApiConfiguration;
|
|
372
363
|
files: { name: string; content: string; declaration: { name: string; content: string } | null }[];
|
|
373
|
-
createFile: (params: {
|
|
374
|
-
path: string;
|
|
375
|
-
fileName: string;
|
|
376
|
-
content: string;
|
|
377
|
-
withPrefix?: boolean;
|
|
378
|
-
}) => void;
|
|
364
|
+
createFile: (params: { path: string; fileName: string; content: string; withPrefix?: boolean }) => void;
|
|
379
365
|
renderTemplate: (
|
|
380
366
|
templateContent: string,
|
|
381
367
|
data: Record<string, unknown>,
|
|
@@ -385,12 +371,6 @@ export interface GenerateApiOutput {
|
|
|
385
371
|
formatTSContent: (content: string) => string;
|
|
386
372
|
}
|
|
387
373
|
|
|
388
|
-
export declare function generateApi(
|
|
389
|
-
|
|
390
|
-
): Promise<GenerateApiOutput>;
|
|
391
|
-
export declare function generateApi(
|
|
392
|
-
params: Omit<GenerateApiParams, "input" | "spec">,
|
|
393
|
-
): Promise<GenerateApiOutput>;
|
|
394
|
-
export declare function generateApi(
|
|
395
|
-
params: Omit<GenerateApiParams, "input" | "url">,
|
|
396
|
-
): Promise<GenerateApiOutput>;
|
|
374
|
+
export declare function generateApi(params: Omit<GenerateApiParams, "url" | "spec">): Promise<GenerateApiOutput>;
|
|
375
|
+
export declare function generateApi(params: Omit<GenerateApiParams, "input" | "spec">): Promise<GenerateApiOutput>;
|
|
376
|
+
export declare function generateApi(params: Omit<GenerateApiParams, "input" | "url">): Promise<GenerateApiOutput>;
|
package/index.js
CHANGED
|
@@ -33,29 +33,20 @@ program
|
|
|
33
33
|
)
|
|
34
34
|
.option(
|
|
35
35
|
"-r, --responses",
|
|
36
|
-
"generate additional information about request responses\n" +
|
|
37
|
-
"also add typings for bad responses",
|
|
36
|
+
"generate additional information about request responses\n" + "also add typings for bad responses",
|
|
38
37
|
false,
|
|
39
38
|
)
|
|
40
39
|
.option("--union-enums", 'generate all "enum" types as union types (T1 | T2 | TN)', false)
|
|
41
40
|
.option("--route-types", "generate type definitions for API routes", false)
|
|
42
41
|
.option("--no-client", "do not generate an API class", false)
|
|
43
|
-
.option(
|
|
44
|
-
"--enum-names-as-values",
|
|
45
|
-
"use values in 'x-enumNames' as enum values (not only as keys)",
|
|
46
|
-
false,
|
|
47
|
-
)
|
|
42
|
+
.option("--enum-names-as-values", "use values in 'x-enumNames' as enum values (not only as keys)", false)
|
|
48
43
|
.option(
|
|
49
44
|
"--extract-request-params",
|
|
50
45
|
"extract request params to data contract (Also combine path params and query params into one object)",
|
|
51
46
|
false,
|
|
52
47
|
)
|
|
53
48
|
.option("--extract-request-body", "extract request body type to data contract", false)
|
|
54
|
-
.option(
|
|
55
|
-
"--modular",
|
|
56
|
-
"generate separated files for http client, data contracts, and routes",
|
|
57
|
-
false,
|
|
58
|
-
)
|
|
49
|
+
.option("--modular", "generate separated files for http client, data contracts, and routes", false)
|
|
59
50
|
.option("--js", "generate js api module with declaration file", false)
|
|
60
51
|
.option(
|
|
61
52
|
"--module-name-index <number>",
|
|
@@ -66,16 +57,15 @@ program
|
|
|
66
57
|
.option("--disableStrictSSL", "disabled strict SSL", false)
|
|
67
58
|
.option("--disableProxy", "disabled proxy", false)
|
|
68
59
|
.option("--axios", "generate axios http client", false)
|
|
60
|
+
.option("--unwrap-response-data", "unwrap the data item from the response", false)
|
|
61
|
+
.option("--disable-throw-on-error", "Do not throw an error when response.ok is not true", false)
|
|
69
62
|
.option("--single-http-client", "Ability to send HttpClient instance to Api constructor", false)
|
|
70
63
|
.option("--silent", "Output only errors to console", false)
|
|
71
64
|
.option("--default-response <type>", "default type for empty response schema", TS_KEYWORDS.VOID)
|
|
72
65
|
.option("--type-prefix <string>", "data contract name prefix", "")
|
|
73
66
|
.option("--type-suffix <string>", "data contract name suffix", "")
|
|
74
|
-
.option(
|
|
75
|
-
|
|
76
|
-
"clean output folder before generate api. WARNING: May cause data loss",
|
|
77
|
-
false,
|
|
78
|
-
);
|
|
67
|
+
.option("--clean-output", "clean output folder before generate api. WARNING: May cause data loss", false)
|
|
68
|
+
.option("--patch", "fix up small errors in the swagger source definition", false);
|
|
79
69
|
|
|
80
70
|
program.parse(process.argv);
|
|
81
71
|
|
|
@@ -100,11 +90,15 @@ const {
|
|
|
100
90
|
disableProxy,
|
|
101
91
|
cleanOutput,
|
|
102
92
|
defaultResponse,
|
|
93
|
+
unwrapResponseData,
|
|
94
|
+
disableThrowOnError,
|
|
95
|
+
sortTypes,
|
|
103
96
|
singleHttpClient,
|
|
104
97
|
axios,
|
|
105
98
|
silent,
|
|
106
99
|
typePrefix,
|
|
107
100
|
typeSuffix,
|
|
101
|
+
patch,
|
|
108
102
|
} = program;
|
|
109
103
|
|
|
110
104
|
generateApi({
|
|
@@ -115,6 +109,9 @@ generateApi({
|
|
|
115
109
|
httpClientType: axios ? HTTP_CLIENT.AXIOS : HTTP_CLIENT.FETCH,
|
|
116
110
|
defaultResponseAsSuccess: defaultAsSuccess,
|
|
117
111
|
defaultResponseType: defaultResponse,
|
|
112
|
+
unwrapResponseData: unwrapResponseData,
|
|
113
|
+
disableThrowOnError: disableThrowOnError,
|
|
114
|
+
sortTypes: sortTypes,
|
|
118
115
|
generateUnionEnums: unionEnums,
|
|
119
116
|
generateResponses: responses,
|
|
120
117
|
extractRequestParams: !!extractRequestParams,
|
|
@@ -134,4 +131,10 @@ generateApi({
|
|
|
134
131
|
silent: !!silent,
|
|
135
132
|
typePrefix,
|
|
136
133
|
typeSuffix,
|
|
134
|
+
patch: !!patch,
|
|
135
|
+
}).catch((err) => {
|
|
136
|
+
// NOTE collect all errors on top level and shows to users in any case
|
|
137
|
+
console.error(err);
|
|
138
|
+
|
|
139
|
+
process.exit(1);
|
|
137
140
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "swagger-typescript-api",
|
|
3
|
-
"version": "9.
|
|
3
|
+
"version": "9.3.1",
|
|
4
4
|
"description": "Generate typescript/javascript api from swagger schema",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"cli:json": "node index.js -r -d -p ./swagger-test-cli.json -n swagger-test-cli.ts",
|
|
@@ -39,13 +39,15 @@
|
|
|
39
39
|
"test:--axios--single-http-client": "node tests/spec/axiosSingleHttpClient/test.js",
|
|
40
40
|
"test:--type-suffix--type-prefix": "node tests/spec/typeSuffixPrefix/test.js",
|
|
41
41
|
"test:partialBaseTemplate": "node tests/spec/partialBaseTemplate/test.js",
|
|
42
|
-
"test:partialDefaultTemplate": "node tests/spec/partialDefaultTemplate/test.js"
|
|
42
|
+
"test:partialDefaultTemplate": "node tests/spec/partialDefaultTemplate/test.js",
|
|
43
|
+
"test:--patch": "node tests/spec/patch/test.js"
|
|
43
44
|
},
|
|
44
45
|
"author": "acacode",
|
|
45
46
|
"license": "MIT",
|
|
46
47
|
"typings": "./index.d.ts",
|
|
47
48
|
"main": "src/index.js",
|
|
48
49
|
"devDependencies": {
|
|
50
|
+
"@types/axios": "^0.14.0",
|
|
49
51
|
"@types/lodash": "^4.14.166",
|
|
50
52
|
"@types/node": "^15.0.2",
|
|
51
53
|
"@types/prettier": "^2.1.6",
|
|
@@ -54,9 +56,10 @@
|
|
|
54
56
|
"pretty-quick": "^3.1.0"
|
|
55
57
|
},
|
|
56
58
|
"dependencies": {
|
|
59
|
+
"axios": "^0.21.4",
|
|
57
60
|
"@types/swagger-schema-official": "2.0.21",
|
|
58
|
-
"axios": "^0.21.1",
|
|
59
61
|
"commander": "^6.2.1",
|
|
62
|
+
"cosmiconfig": "^7.0.0",
|
|
60
63
|
"eta": "^1.12.1",
|
|
61
64
|
"js-yaml": "^4.0.0",
|
|
62
65
|
"lodash": "^4.17.21",
|
package/src/config.js
CHANGED
|
@@ -58,6 +58,9 @@ const config = {
|
|
|
58
58
|
defaultResponseType: TS_KEYWORDS.VOID,
|
|
59
59
|
singleHttpClient: false,
|
|
60
60
|
httpClientType: HTTP_CLIENT.FETCH,
|
|
61
|
+
unwrapResponseData: false,
|
|
62
|
+
disableThrowOnError: false,
|
|
63
|
+
sortTypes: false,
|
|
61
64
|
templatePaths: {
|
|
62
65
|
/** `templates/base` */
|
|
63
66
|
base: "",
|
|
@@ -82,6 +85,7 @@ const config = {
|
|
|
82
85
|
silent: false,
|
|
83
86
|
typePrefix: "",
|
|
84
87
|
typeSuffix: "",
|
|
88
|
+
patch: false,
|
|
85
89
|
componentTypeNameResolver: new NameResolver([]),
|
|
86
90
|
};
|
|
87
91
|
|
package/src/index.js
CHANGED
|
@@ -21,6 +21,7 @@ const { generateOutputFiles } = require("./output");
|
|
|
21
21
|
const formatFileContent = require("./formatFileContent");
|
|
22
22
|
const { logger } = require("./logger");
|
|
23
23
|
const { ComponentTypeNameResolver } = require("./utils/resolveName");
|
|
24
|
+
const { getPrettierOptions } = require("./prettierOptions");
|
|
24
25
|
|
|
25
26
|
module.exports = {
|
|
26
27
|
constants: constants,
|
|
@@ -44,8 +45,11 @@ module.exports = {
|
|
|
44
45
|
extractRequestParams = config.extractRequestParams,
|
|
45
46
|
extractRequestBody = config.extractRequestBody,
|
|
46
47
|
defaultResponseType = config.defaultResponseType,
|
|
48
|
+
unwrapResponseData = config.unwrapResponseData,
|
|
49
|
+
disableThrowOnError = config.disableThrowOnError,
|
|
50
|
+
sortTypes = config.sortTypes,
|
|
47
51
|
singleHttpClient = config.singleHttpClient,
|
|
48
|
-
prettier: prettierOptions =
|
|
52
|
+
prettier: prettierOptions = getPrettierOptions(),
|
|
49
53
|
hooks: rawHooks,
|
|
50
54
|
extraTemplates,
|
|
51
55
|
enumNamesAsValues,
|
|
@@ -55,6 +59,7 @@ module.exports = {
|
|
|
55
59
|
silent = config.silent,
|
|
56
60
|
typePrefix = config.typePrefix,
|
|
57
61
|
typeSuffix = config.typeSuffix,
|
|
62
|
+
patch = config.patch,
|
|
58
63
|
}) =>
|
|
59
64
|
new Promise((resolve, reject) => {
|
|
60
65
|
addToConfig({
|
|
@@ -77,16 +82,20 @@ module.exports = {
|
|
|
77
82
|
disableProxy,
|
|
78
83
|
cleanOutput,
|
|
79
84
|
defaultResponseType,
|
|
85
|
+
unwrapResponseData,
|
|
86
|
+
disableThrowOnError,
|
|
87
|
+
sortTypes,
|
|
80
88
|
singleHttpClient,
|
|
81
89
|
constants,
|
|
82
90
|
silent,
|
|
83
91
|
toJS: translateToJavaScript,
|
|
84
92
|
typePrefix,
|
|
85
93
|
typeSuffix,
|
|
94
|
+
patch,
|
|
86
95
|
});
|
|
87
96
|
(spec
|
|
88
|
-
? convertSwaggerObject(spec)
|
|
89
|
-
: getSwaggerObject(input, url, disableStrictSSL, disableProxy)
|
|
97
|
+
? convertSwaggerObject(spec, { patch })
|
|
98
|
+
: getSwaggerObject(input, url, disableStrictSSL, disableProxy, { patch })
|
|
90
99
|
)
|
|
91
100
|
.then(({ usageSchema, originalSchema }) => {
|
|
92
101
|
const templatePaths = getTemplatePaths(config);
|
|
@@ -136,11 +145,41 @@ module.exports = {
|
|
|
136
145
|
const hasFormDataRoutes = routes.some((route) => route.hasFormDataParams);
|
|
137
146
|
|
|
138
147
|
const usageComponentSchemas = filterComponentsMap(componentsMap, "schemas");
|
|
148
|
+
const sortByProperty = (o1, o2, propertyName) => {
|
|
149
|
+
if(o1[propertyName] > o2[propertyName]) {
|
|
150
|
+
return 1;
|
|
151
|
+
}
|
|
152
|
+
if(o1[propertyName] < o2[propertyName]) {
|
|
153
|
+
return -1;
|
|
154
|
+
}
|
|
155
|
+
return 0;
|
|
156
|
+
}
|
|
157
|
+
const sortByTypeName = (o1, o2) => sortByProperty(o1, o2, 'typeName');
|
|
158
|
+
|
|
159
|
+
const sortByName = (o1, o2) => sortByProperty(o1, o2, 'name');
|
|
160
|
+
|
|
161
|
+
const sortSchemas = (schemas) => {
|
|
162
|
+
if(config.sortTypes) {
|
|
163
|
+
return schemas.sort(sortByTypeName).map((schema) => {
|
|
164
|
+
if(schema.rawTypeData?.properties) {
|
|
165
|
+
return {
|
|
166
|
+
...schema,
|
|
167
|
+
rawTypeData: {
|
|
168
|
+
...schema.rawTypeData,
|
|
169
|
+
'$parsed': {...schema.rawTypeData['$parsed'], content: schema.rawTypeData['$parsed'].content.sort(sortByName)}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return schema;
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
return schemas;
|
|
177
|
+
};
|
|
139
178
|
|
|
140
179
|
const rawConfiguration = {
|
|
141
180
|
apiConfig: createApiConfig(usageSchema),
|
|
142
181
|
config,
|
|
143
|
-
modelTypes: _.map(usageComponentSchemas, prepareModelType),
|
|
182
|
+
modelTypes: _.map(sortSchemas(usageComponentSchemas), prepareModelType),
|
|
144
183
|
rawModelTypes: usageComponentSchemas,
|
|
145
184
|
hasFormDataRoutes,
|
|
146
185
|
hasSecurityRoutes,
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
const { cosmiconfigSync } = require("cosmiconfig");
|
|
2
|
+
const constants = require("./constants");
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Get prettier options from user's project or return the default one
|
|
6
|
+
* @return {import('prettier').Options} Prettier options
|
|
7
|
+
*/
|
|
8
|
+
function getPrettierOptions() {
|
|
9
|
+
const prettier = cosmiconfigSync("prettier").search();
|
|
10
|
+
|
|
11
|
+
if (prettier) {
|
|
12
|
+
return {
|
|
13
|
+
...prettier.config,
|
|
14
|
+
parser: "typescript",
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return constants.PRETTIER_OPTIONS;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
module.exports = {
|
|
22
|
+
getPrettierOptions,
|
|
23
|
+
};
|
package/src/routes.js
CHANGED
|
@@ -2,6 +2,7 @@ const _ = require("lodash");
|
|
|
2
2
|
const {
|
|
3
3
|
types,
|
|
4
4
|
parseSchema,
|
|
5
|
+
getType,
|
|
5
6
|
getRefType,
|
|
6
7
|
getInlineParseContent,
|
|
7
8
|
checkAndAddNull,
|
|
@@ -475,6 +476,21 @@ const getResponseBodyInfo = (routeInfo, routeParams, parsedSchemas) => {
|
|
|
475
476
|
(response) => !response.isSuccess && response.type !== TS_KEYWORDS.ANY,
|
|
476
477
|
);
|
|
477
478
|
|
|
479
|
+
const handleResponseHeaders = (src) => {
|
|
480
|
+
if (!src) {
|
|
481
|
+
return "headers: {},";
|
|
482
|
+
}
|
|
483
|
+
const headerTypes = Object.fromEntries(
|
|
484
|
+
Object.entries(src).map(([k, v]) => {
|
|
485
|
+
return [k, getType(v)];
|
|
486
|
+
}),
|
|
487
|
+
);
|
|
488
|
+
const r = `headers: { ${Object.entries(headerTypes)
|
|
489
|
+
.map(([k, v]) => `"${k}": ${v}`)
|
|
490
|
+
.join(",")} },`;
|
|
491
|
+
return r;
|
|
492
|
+
};
|
|
493
|
+
|
|
478
494
|
return {
|
|
479
495
|
contentTypes,
|
|
480
496
|
responses: responseInfos,
|
|
@@ -486,6 +502,19 @@ const getResponseBodyInfo = (routeInfo, routeParams, parsedSchemas) => {
|
|
|
486
502
|
schemas: errorResponses,
|
|
487
503
|
type: _.uniq(errorResponses.map((response) => response.type)).join(" | ") || TS_KEYWORDS.ANY,
|
|
488
504
|
},
|
|
505
|
+
full: {
|
|
506
|
+
types:
|
|
507
|
+
responseInfos
|
|
508
|
+
.map(
|
|
509
|
+
(response) => `{
|
|
510
|
+
data: ${response.type}, status: ${response.status}, statusCode: ${
|
|
511
|
+
response.status
|
|
512
|
+
}, statusText: "${response.description}", ${handleResponseHeaders(
|
|
513
|
+
response.headers,
|
|
514
|
+
)} config: {} }`,
|
|
515
|
+
)
|
|
516
|
+
.join(" | ") || TS_KEYWORDS.ANY,
|
|
517
|
+
},
|
|
489
518
|
};
|
|
490
519
|
};
|
|
491
520
|
|
|
@@ -685,6 +714,7 @@ const parseRoutes = ({
|
|
|
685
714
|
contentTypes: responseBodyInfo.contentTypes,
|
|
686
715
|
type: responseBodyInfo.success.type,
|
|
687
716
|
errorType: responseBodyInfo.error.type,
|
|
717
|
+
fullTypes: responseBodyInfo.full.types,
|
|
688
718
|
},
|
|
689
719
|
raw: rawRouteInfo,
|
|
690
720
|
};
|
package/src/schema.js
CHANGED
package/src/swagger.js
CHANGED
|
@@ -18,7 +18,7 @@ const parseSwaggerFile = (file) => {
|
|
|
18
18
|
};
|
|
19
19
|
|
|
20
20
|
const getSwaggerFile = (pathToSwagger, urlToSwagger, disableStrictSSL, disableProxy) =>
|
|
21
|
-
new Promise((resolve) => {
|
|
21
|
+
new Promise((resolve, reject) => {
|
|
22
22
|
if (pathIsExist(pathToSwagger)) {
|
|
23
23
|
logger.log(`try to get swagger by path "${pathToSwagger}"`);
|
|
24
24
|
resolve(getFileContent(pathToSwagger));
|
|
@@ -38,16 +38,28 @@ const getSwaggerFile = (pathToSwagger, urlToSwagger, disableStrictSSL, disablePr
|
|
|
38
38
|
axios
|
|
39
39
|
.get(urlToSwagger, axiosOptions)
|
|
40
40
|
.then((res) => resolve(res.data))
|
|
41
|
-
.catch((
|
|
41
|
+
.catch(() => {
|
|
42
|
+
const message = `error while getting swagger by URL ${urlToSwagger}`;
|
|
43
|
+
|
|
44
|
+
logger.error(message);
|
|
45
|
+
|
|
46
|
+
reject(message);
|
|
47
|
+
});
|
|
42
48
|
}
|
|
43
49
|
});
|
|
44
50
|
|
|
45
|
-
const getSwaggerObject = (
|
|
51
|
+
const getSwaggerObject = (
|
|
52
|
+
pathToSwagger,
|
|
53
|
+
urlToSwagger,
|
|
54
|
+
disableStrictSSL,
|
|
55
|
+
disableProxy,
|
|
56
|
+
converterOptions,
|
|
57
|
+
) =>
|
|
46
58
|
getSwaggerFile(pathToSwagger, urlToSwagger, disableStrictSSL, disableProxy).then((file) =>
|
|
47
|
-
convertSwaggerObject(parseSwaggerFile(file)),
|
|
59
|
+
convertSwaggerObject(parseSwaggerFile(file), converterOptions),
|
|
48
60
|
);
|
|
49
61
|
|
|
50
|
-
const convertSwaggerObject = (swaggerSchema) => {
|
|
62
|
+
const convertSwaggerObject = (swaggerSchema, converterOptions) => {
|
|
51
63
|
return new Promise((resolve) => {
|
|
52
64
|
swaggerSchema.info = _.merge(
|
|
53
65
|
{
|
|
@@ -63,6 +75,7 @@ const convertSwaggerObject = (swaggerSchema) => {
|
|
|
63
75
|
converter.convertObj(
|
|
64
76
|
swaggerSchema,
|
|
65
77
|
{
|
|
78
|
+
...converterOptions,
|
|
66
79
|
warnOnly: true,
|
|
67
80
|
refSiblings: "preserve",
|
|
68
81
|
rbname: "requestBodyName",
|
package/src/typeFormatters.js
CHANGED
|
@@ -18,10 +18,10 @@ const formatters = {
|
|
|
18
18
|
const extraSpace = " ";
|
|
19
19
|
const result = `${extraSpace}${part.field};\n`;
|
|
20
20
|
|
|
21
|
-
const comments = _.compact([part.title, part.description]).reduce(
|
|
21
|
+
const comments = _.uniq(_.compact([part.title, part.description]).reduce(
|
|
22
22
|
(acc, comment) => [...acc, ...comment.split(/\n/g)],
|
|
23
23
|
[],
|
|
24
|
-
);
|
|
24
|
+
));
|
|
25
25
|
|
|
26
26
|
const commonText = comments.length
|
|
27
27
|
? [
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<%
|
|
2
|
-
const { apiConfig, generateResponses } = it;
|
|
2
|
+
const { apiConfig, generateResponses, config } = it;
|
|
3
3
|
%>
|
|
4
4
|
|
|
5
5
|
import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse, ResponseType } from "axios";
|
|
@@ -89,7 +89,11 @@ export class HttpClient<SecurityDataType = unknown> {
|
|
|
89
89
|
format,
|
|
90
90
|
body,
|
|
91
91
|
...params
|
|
92
|
+
<% if (config.unwrapResponseData) { %>
|
|
93
|
+
}: FullRequestParams): Promise<T> => {
|
|
94
|
+
<% } else { %>
|
|
92
95
|
}: FullRequestParams): Promise<AxiosResponse<T>> => {
|
|
96
|
+
<% } %>
|
|
93
97
|
const secureParams = ((typeof secure === 'boolean' ? secure : this.secure) && this.securityWorker && (await this.securityWorker(this.securityData))) || {};
|
|
94
98
|
const requestParams = this.mergeRequestParams(params, secureParams);
|
|
95
99
|
const responseFormat = (format && this.format) || void 0;
|
|
@@ -99,7 +103,7 @@ export class HttpClient<SecurityDataType = unknown> {
|
|
|
99
103
|
requestParams.headers.post = {};
|
|
100
104
|
requestParams.headers.put = {};
|
|
101
105
|
|
|
102
|
-
|
|
106
|
+
body = this.createFormData(body as Record<string, unknown>);
|
|
103
107
|
}
|
|
104
108
|
|
|
105
109
|
return this.instance.request({
|
|
@@ -112,6 +116,10 @@ export class HttpClient<SecurityDataType = unknown> {
|
|
|
112
116
|
responseType: responseFormat,
|
|
113
117
|
data: body,
|
|
114
118
|
url: path,
|
|
119
|
+
<% if (config.unwrapResponseData) { %>
|
|
120
|
+
}).then(response => response.data);
|
|
121
|
+
<% } else { %>
|
|
115
122
|
});
|
|
123
|
+
<% } %>
|
|
116
124
|
};
|
|
117
125
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<%
|
|
2
|
-
const { apiConfig, generateResponses } = it;
|
|
2
|
+
const { apiConfig, generateResponses, config } = it;
|
|
3
3
|
%>
|
|
4
4
|
|
|
5
5
|
export type QueryParamsType = Record<string | number, any>;
|
|
@@ -164,7 +164,11 @@ export class HttpClient<SecurityDataType = unknown> {
|
|
|
164
164
|
baseUrl,
|
|
165
165
|
cancelToken,
|
|
166
166
|
...params
|
|
167
|
+
<% if (config.unwrapResponseData) { %>
|
|
168
|
+
}: FullRequestParams): Promise<T> => {
|
|
169
|
+
<% } else { %>
|
|
167
170
|
}: FullRequestParams): Promise<HttpResponse<T, E>> => {
|
|
171
|
+
<% } %>
|
|
168
172
|
const secureParams = ((typeof secure === 'boolean' ? secure : this.baseApiParams.secure) && this.securityWorker && await this.securityWorker(this.securityData)) || {};
|
|
169
173
|
const requestParams = this.mergeRequestParams(params, secureParams);
|
|
170
174
|
const queryString = query && this.toQueryString(query);
|
|
@@ -205,8 +209,14 @@ export class HttpClient<SecurityDataType = unknown> {
|
|
|
205
209
|
this.abortControllers.delete(cancelToken);
|
|
206
210
|
}
|
|
207
211
|
|
|
212
|
+
<% if (!config.disableThrowOnError) { %>
|
|
208
213
|
if (!response.ok) throw data;
|
|
214
|
+
<% } %>
|
|
215
|
+
<% if (config.unwrapResponseData) { %>
|
|
216
|
+
return data.data;
|
|
217
|
+
<% } else { %>
|
|
209
218
|
return data;
|
|
219
|
+
<% } %>
|
|
210
220
|
});
|
|
211
221
|
};
|
|
212
222
|
}
|
|
@@ -39,7 +39,11 @@ const descriptionLines = _.compact([
|
|
|
39
39
|
export class Api<SecurityDataType extends unknown><% if (!config.singleHttpClient) { %> extends HttpClient<SecurityDataType> <% } %> {
|
|
40
40
|
|
|
41
41
|
<% if(config.singleHttpClient) { %>
|
|
42
|
-
|
|
42
|
+
http: HttpClient<SecurityDataType>;
|
|
43
|
+
|
|
44
|
+
constructor (http: HttpClient<SecurityDataType>) {
|
|
45
|
+
this.http = http;
|
|
46
|
+
}
|
|
43
47
|
<% } %>
|
|
44
48
|
|
|
45
49
|
|
|
@@ -8,15 +8,18 @@ const dataContracts = _.map(modelTypes, "name");
|
|
|
8
8
|
|
|
9
9
|
<% if (config.httpClientType === config.constants.HTTP_CLIENT.AXIOS) { %> import { AxiosRequestConfig, AxiosResponse } from "axios"; <% } %>
|
|
10
10
|
|
|
11
|
-
import { HttpClient, RequestParams, ContentType } from "./<%~ config.fileNames.httpClient %>";
|
|
11
|
+
import { HttpClient, RequestParams, ContentType, HttpResponse } from "./<%~ config.fileNames.httpClient %>";
|
|
12
12
|
<% if (dataContracts.length) { %>
|
|
13
13
|
import { <%~ dataContracts.join(", ") %> } from "./<%~ config.fileNames.dataContracts %>"
|
|
14
14
|
<% } %>
|
|
15
15
|
|
|
16
16
|
export class <%= apiClassName %><SecurityDataType = unknown><% if (!config.singleHttpClient) { %> extends HttpClient<SecurityDataType> <% } %> {
|
|
17
|
-
|
|
18
17
|
<% if(config.singleHttpClient) { %>
|
|
19
|
-
|
|
18
|
+
http: HttpClient<SecurityDataType>;
|
|
19
|
+
|
|
20
|
+
constructor (http: HttpClient<SecurityDataType>) {
|
|
21
|
+
this.http = http;
|
|
22
|
+
}
|
|
20
23
|
<% } %>
|
|
21
24
|
|
|
22
25
|
<% routes.forEach((route) => { %>
|