swagger-typescript-api 9.3.0 → 10.0.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 CHANGED
@@ -1,4 +1,43 @@
1
- # next release
1
+ # next release
2
+
3
+ # 10.0.1
4
+
5
+ - fix problem linked with [this.name is not a function](https://github.com/acacode/swagger-typescript-api/issues/381)
6
+ - [internal] add cli tests
7
+ - fix problem with not correct working the `--no-client` option
8
+
9
+ # 10.0.0
10
+
11
+ - `--extract-response-body` option - extract response body type to data contract
12
+ - `--extract-response-error` option - extract response error type to data contract
13
+ - `--add-readonly` option - generate readonly properties
14
+ - `authorizationToken` for axios fetch swagger schema request
15
+ - fix: change COMPLEX_NOT_OF to COMPLEX_NOT (internal)
16
+ - feat: improve `@deprecated` jsdoc info
17
+ - feat: improve `required` field in complex data schemas (anyOf, oneOf, allOf etc)
18
+ - feat: abortSignal for fetch http client
19
+ - chore: improve typings in index.d.ts
20
+ - fixed [Request falls if FormData attachment is File instance](https://github.com/acacode/swagger-typescript-api/issues/293)
21
+ - fixed [Response format - global default or override ?](https://github.com/acacode/swagger-typescript-api/issues/251)
22
+
23
+ > Co-authored-by: Sergey S. Volkov <js2me@outlook.com>
24
+ > Co-authored-by: Xavier Cassel <57092100+xcassel@users.noreply.github.com>
25
+ > Co-authored-by: cassel <xavier.cassel35@gmail.com>
26
+ > Co-authored-by: Adrian Wieprzkowicz <Argeento@users.noreply.github.com>
27
+ > Co-authored-by: EvgenBabenko <evgen.babenko@gmail.com>
28
+ > Co-authored-by: RoCat <catoio.romain@gmail.com>
29
+ > Co-authored-by: rcatoio <rcatoio@doubletrade.com>
30
+ > Co-authored-by: 卡色 <cipchk@qq.com>
31
+ > Co-authored-by: 江麻妞 <50100681+jiangmaniu@users.noreply.github.com>
32
+ > Co-authored-by: Kasper Moskwiak <kasper.moskwiak@gmail.com>
33
+ > Co-authored-by: Ben Watkins <ben@outdatedversion.com>
34
+ > Co-authored-by: bonukai <bonukai@protonmail.com>
35
+ > Co-authored-by: baggoedw <92381702+baggoedw@users.noreply.github.com>
36
+ > Co-authored-by: Marcus Dunn <51931484+MarcusDunn@users.noreply.github.com>
37
+ > Co-authored-by: Daniele De Matteo <daniele@kuama.net>
38
+ > Co-authored-by: Daniel Playfair Cal <daniel.playfair.cal@gmail.com>
39
+ > Co-authored-by: Anders Cassidy <anders.cassidy@dailypay.com>
40
+ > Co-authored-by: Daniel Playfair Cal <dcal@atlassian.com>
2
41
 
3
42
  # 9.2.0
4
43
 
package/README.md CHANGED
@@ -19,7 +19,11 @@ Any questions you can ask [**here**](https://github.com/acacode/swagger-typescri
19
19
 
20
20
  <br>
21
21
 
22
- ![](https://raw.githubusercontent.com/acacode/swagger-typescript-api/master/assets/components-converter-example.jpg)
22
+ ![](https://raw.githubusercontent.com/acacode/swagger-typescript-api/master/assets/components-converter-example.jpg)
23
+
24
+ 👀 This project is looking for a code maintainer 👀
25
+ P.S. If you are creating the PR, please check your changes with using command `npm run prepare`
26
+ P.S. If you want to contribute please use branch `next`. All PRs which will have target `master` will be declined
23
27
 
24
28
  ## 👀 Examples
25
29
 
@@ -33,36 +37,39 @@ Usage: swagger-typescript-api [options]
33
37
 
34
38
  Options:
35
39
  -v, --version output the current version
36
- -p, --path <path> path/url to swagger scheme
37
- -o, --output <output> output path of typescript api file (default: "./")
38
- -n, --name <name> name of output typescript api file (default: "Api.ts")
39
- -t, --templates <path> path to folder containing templates
40
+ -p, --path <string> path/url to swagger scheme
41
+ -o, --output <string> output path of typescript api file (default: "./")
42
+ -n, --name <string> name of output typescript api file (default: "Api.ts")
43
+ -t, --templates <string> path to folder containing templates
40
44
  -d, --default-as-success use "default" response status code as success response too.
41
- some swagger schemas use "default" response status code
42
- as success response type by default. (default: false)
45
+ some swagger schemas use "default" response status code as success response type by default. (default: false)
43
46
  -r, --responses generate additional information about request responses
44
47
  also add typings for bad responses (default: false)
45
48
  --union-enums generate all "enum" types as union types (T1 | T2 | TN) (default: false)
49
+ --add-readonly generate readonly properties (default: false)
46
50
  --route-types generate type definitions for API routes (default: false)
47
51
  --no-client do not generate an API class
48
52
  --enum-names-as-values use values in 'x-enumNames' as enum values (not only as keys) (default: false)
49
- --js generate js api module with declaration file (default: false)
50
- --extract-request-params extract request params to data contract (default: false)
51
- Also combine path params and query params into one object
52
- --extract-request-body extract request body type to data contract (default: false)
53
- --module-name-index <number> determines which path index should be used for routes separation (default: 0)
54
- (example: GET:/fruites/getFruit -> index:0 -> moduleName -> fruites)
55
- --module-name-first-tag splits routes based on the first tag
53
+ --extract-request-params extract request params to data contract (Also combine path params and query params into one object) (default: false)
54
+ --extract-request-body extract request body type to data contract (default: false)
55
+ --extract-response-body extract response body type to data contract (default: false)
56
+ --extract-response-error extract response error type to data contract (default: false)
56
57
  --modular generate separated files for http client, data contracts, and routes (default: false)
58
+ --js generate js api module with declaration file (default: false)
59
+ --module-name-index <number> determines which path index should be used for routes separation (example: GET:/fruites/getFruit -> index:0 -> moduleName -> fruites) (default: 0)
60
+ --module-name-first-tag splits routes based on the first tag (default: false)
57
61
  --disableStrictSSL disabled strict SSL (default: false)
58
62
  --disableProxy disabled proxy (default: false)
59
- --clean-output clean output folder before generate api. WARNING: May cause data loss (default: false)
60
63
  --axios generate axios http client (default: false)
64
+ --unwrap-response-data unwrap the data item from the response (default: false)
65
+ --disable-throw-on-error Do not throw an error when response.ok is not true (default: false)
61
66
  --single-http-client Ability to send HttpClient instance to Api constructor (default: false)
62
67
  --silent Output only errors to console (default: false)
63
68
  --default-response <type> default type for empty response schema (default: "void")
64
69
  --type-prefix <string> data contract name prefix (default: "")
65
70
  --type-suffix <string> data contract name suffix (default: "")
71
+ --clean-output clean output folder before generate api. WARNING: May cause data loss (default: false)
72
+ --api-class-name <string> name of the api class
66
73
  --patch fix up small errors in the swagger source definition (default: false)
67
74
  -h, --help display help for command
68
75
  ```
package/index.d.ts CHANGED
@@ -1,19 +1,4 @@
1
- interface GenerateApiParams {
2
- /**
3
- * path to swagger schema
4
- */
5
- input: string;
6
-
7
- /**
8
- * url to swagger schema
9
- */
10
- url: string;
11
-
12
- /**
13
- * swagger schema JSON
14
- */
15
- spec: import("swagger-schema-official").Spec;
16
-
1
+ interface GenerateApiParamsBase {
17
2
  /**
18
3
  * default 'api.ts'
19
4
  */
@@ -25,7 +10,7 @@ interface GenerateApiParams {
25
10
  output?: string;
26
11
 
27
12
  /**
28
- * path to folder containing templates (default: ./scr/templates)
13
+ * path to folder containing templates (default: ./src/templates)
29
14
  */
30
15
  templates?: string;
31
16
 
@@ -92,6 +77,14 @@ interface GenerateApiParams {
92
77
  * extract request body type to data contract
93
78
  */
94
79
  extractRequestBody?: boolean;
80
+ /**
81
+ * extract response body type to data contract
82
+ */
83
+ extractResponseBody?: boolean;
84
+ /**
85
+ * extract response error type to data contract
86
+ */
87
+ extractResponseError?: boolean;
95
88
  /**
96
89
  * prettier configuration
97
90
  */
@@ -121,8 +114,35 @@ interface GenerateApiParams {
121
114
  * fix up small errors in the swagger source definition
122
115
  */
123
116
  patch?: boolean;
117
+ /**
118
+ * authorization token
119
+ */
120
+ authorizationToken?: string;
121
+ }
122
+
123
+ interface GenerateApiParamsFromPath extends GenerateApiParamsBase {
124
+ /**
125
+ * path to swagger schema
126
+ */
127
+ input: string;
128
+ }
129
+
130
+ interface GenerateApiParamsFromUrl extends GenerateApiParamsBase {
131
+ /**
132
+ * url to swagger schema
133
+ */
134
+ url: string;
135
+ }
136
+
137
+ interface GenerateApiParamsFromSpecLiteral extends GenerateApiParamsBase {
138
+ /**
139
+ * swagger schema JSON
140
+ */
141
+ spec: import("swagger-schema-official").Spec;
124
142
  }
125
143
 
144
+ export type GenerateApiParams = GenerateApiParamsFromPath | GenerateApiParamsFromUrl | GenerateApiParamsFromSpecLiteral;
145
+
126
146
  export interface Hooks {
127
147
  /** calls after parse schema component */
128
148
  onCreateComponent: (component: SchemaComponent) => SchemaComponent | void;
@@ -323,6 +343,7 @@ export interface GenerateApiConfiguration {
323
343
  routeName: string;
324
344
  };
325
345
  routeNameDuplicatesMap: Map<string, string>;
346
+ apiClassName: string
326
347
  };
327
348
  modelTypes: ModelType[];
328
349
  rawModelTypes: SchemaComponent[];
@@ -371,6 +392,4 @@ export interface GenerateApiOutput {
371
392
  formatTSContent: (content: string) => string;
372
393
  }
373
394
 
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>;
395
+ export declare function generateApi(params: GenerateApiParams): Promise<GenerateApiOutput>;
package/index.js CHANGED
@@ -14,17 +14,14 @@ const { TS_KEYWORDS, HTTP_CLIENT } = require("./src/constants");
14
14
 
15
15
  const program = new Command(packageName);
16
16
 
17
- program.storeOptionsAsProperties(true);
18
-
19
- program
17
+ const options = program
18
+ .alias("sta")
20
19
  .version(version, "-v, --version", "output the current version")
21
- .description("Generate api via swagger scheme.\nSupports OA 3.0, 2.0, JSON, yaml.");
22
-
23
- program
24
- .requiredOption("-p, --path <path>", "path/url to swagger scheme")
25
- .option("-o, --output <output>", "output path of typescript api file", "./")
26
- .option("-n, --name <name>", "name of output typescript api file", "Api.ts")
27
- .option("-t, --templates <path>", "path to folder containing templates")
20
+ .description("Generate api via swagger scheme.\nSupports OA 3.0, 2.0, JSON, yaml.")
21
+ .requiredOption("-p, --path <string>", "path/url to swagger scheme")
22
+ .option("-o, --output <string>", "output path of typescript api file", "./")
23
+ .option("-n, --name <string>", "name of output typescript api file", "Api.ts")
24
+ .option("-t, --templates <string>", "path to folder containing templates")
28
25
  .option(
29
26
  "-d, --default-as-success",
30
27
  'use "default" response status code as success response too.\n' +
@@ -37,8 +34,9 @@ program
37
34
  false,
38
35
  )
39
36
  .option("--union-enums", 'generate all "enum" types as union types (T1 | T2 | TN)', false)
37
+ .option("--add-readonly", "generate readonly properties", false)
40
38
  .option("--route-types", "generate type definitions for API routes", false)
41
- .option("--no-client", "do not generate an API class", false)
39
+ .option("--no-client", "do not generate an API class", true)
42
40
  .option("--enum-names-as-values", "use values in 'x-enumNames' as enum values (not only as keys)", false)
43
41
  .option(
44
42
  "--extract-request-params",
@@ -46,6 +44,8 @@ program
46
44
  false,
47
45
  )
48
46
  .option("--extract-request-body", "extract request body type to data contract", false)
47
+ .option("--extract-response-body", "extract response body type to data contract", false)
48
+ .option("--extract-response-error", "extract response error type to data contract", false)
49
49
  .option("--modular", "generate separated files for http client, data contracts, and routes", false)
50
50
  .option("--js", "generate js api module with declaration file", false)
51
51
  .option(
@@ -65,73 +65,46 @@ program
65
65
  .option("--type-prefix <string>", "data contract name prefix", "")
66
66
  .option("--type-suffix <string>", "data contract name suffix", "")
67
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);
69
-
70
- program.parse(process.argv);
71
-
72
- const {
73
- path,
74
- output,
75
- name,
76
- templates,
77
- unionEnums,
78
- routeTypes,
79
- client,
80
- defaultAsSuccess,
81
- responses,
82
- modular,
83
- js,
84
- moduleNameIndex,
85
- moduleNameFirstTag,
86
- extractRequestParams,
87
- extractRequestBody,
88
- enumNamesAsValues,
89
- disableStrictSSL,
90
- disableProxy,
91
- cleanOutput,
92
- defaultResponse,
93
- unwrapResponseData,
94
- disableThrowOnError,
95
- sortTypes,
96
- singleHttpClient,
97
- axios,
98
- silent,
99
- typePrefix,
100
- typeSuffix,
101
- patch,
102
- } = program;
68
+ .option("--api-class-name <string>", "name of the api class")
69
+ .option("--patch", "fix up small errors in the swagger source definition", false)
70
+ .parse(process.argv)
71
+ .opts();
103
72
 
104
73
  generateApi({
105
- name,
106
- url: path,
107
- generateRouteTypes: routeTypes,
108
- generateClient: !!(axios || client),
109
- httpClientType: axios ? HTTP_CLIENT.AXIOS : HTTP_CLIENT.FETCH,
110
- defaultResponseAsSuccess: defaultAsSuccess,
111
- defaultResponseType: defaultResponse,
112
- unwrapResponseData: unwrapResponseData,
113
- disableThrowOnError: disableThrowOnError,
114
- sortTypes: sortTypes,
115
- generateUnionEnums: unionEnums,
116
- generateResponses: responses,
117
- extractRequestParams: !!extractRequestParams,
118
- extractRequestBody: !!extractRequestBody,
119
- input: resolve(process.cwd(), path),
120
- output: resolve(process.cwd(), output || "."),
121
- templates,
122
- modular: !!modular,
123
- toJS: !!js,
124
- enumNamesAsValues: enumNamesAsValues,
125
- moduleNameIndex: +(moduleNameIndex || 0),
126
- moduleNameFirstTag: moduleNameFirstTag,
127
- disableStrictSSL: !!disableStrictSSL,
128
- disableProxy: !!disableProxy,
129
- singleHttpClient: !!singleHttpClient,
130
- cleanOutput: !!cleanOutput,
131
- silent: !!silent,
132
- typePrefix,
133
- typeSuffix,
134
- patch: !!patch,
74
+ name: options.name,
75
+ url: options.path,
76
+ generateRouteTypes: options.routeTypes,
77
+ generateClient: !!(options.axios || options.client),
78
+ httpClientType: options.axios ? HTTP_CLIENT.AXIOS : HTTP_CLIENT.FETCH,
79
+ defaultResponseAsSuccess: options.defaultAsSuccess,
80
+ defaultResponseType: options.defaultResponse,
81
+ unwrapResponseData: options.unwrapResponseData,
82
+ disableThrowOnError: options.disableThrowOnError,
83
+ sortTypes: options.sortTypes,
84
+ generateUnionEnums: options.unionEnums,
85
+ addReadonly: options.addReadonly,
86
+ generateResponses: options.responses,
87
+ extractRequestParams: !!options.extractRequestParams,
88
+ extractRequestBody: !!options.extractRequestBody,
89
+ extractResponseBody: !!options.extractResponseBody,
90
+ extractResponseError: !!options.extractResponseError,
91
+ input: resolve(process.cwd(), options.path),
92
+ output: resolve(process.cwd(), options.output || "."),
93
+ templates: options.templates,
94
+ modular: !!options.modular,
95
+ toJS: !!options.js,
96
+ enumNamesAsValues: options.enumNamesAsValues,
97
+ moduleNameIndex: +(options.moduleNameIndex || 0),
98
+ moduleNameFirstTag: options.moduleNameFirstTag,
99
+ disableStrictSSL: !!options.disableStrictSSL,
100
+ disableProxy: !!options.disableProxy,
101
+ singleHttpClient: !!options.singleHttpClient,
102
+ cleanOutput: !!options.cleanOutput,
103
+ silent: !!options.silent,
104
+ typePrefix: options.typePrefix,
105
+ typeSuffix: options.typeSuffix,
106
+ patch: !!options.patch,
107
+ apiClassName: options.apiClassName,
135
108
  }).catch((err) => {
136
109
  // NOTE collect all errors on top level and shows to users in any case
137
110
  console.error(err);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "swagger-typescript-api",
3
- "version": "9.3.0",
3
+ "version": "10.0.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",
@@ -23,6 +23,7 @@
23
23
  "test:--default-as-success": "node tests/spec/defaultAsSuccess/test.js",
24
24
  "test:--templates": "node tests/spec/templates/test.js",
25
25
  "test:--union-enums": "node tests/spec/unionEnums/test.js",
26
+ "test:--add-readonly": "node tests/spec/readonly/test.js",
26
27
  "test:--responses": "node tests/spec/responses/test.js",
27
28
  "test:specProperty": "node tests/spec/specProperty/test.js",
28
29
  "test:--module-name-index": "node tests/spec/moduleNameIndex/test.js",
@@ -31,6 +32,8 @@
31
32
  "test:--single-http-client": "node tests/spec/singleHttpClient/test.js",
32
33
  "test:--extract-request-params": "node tests/spec/extractRequestParams/test.js",
33
34
  "test:--extract-request-body": "node tests/spec/extractRequestBody/test.js",
35
+ "test:--extract-response-body": "node tests/spec/extractResponseBody/test.js",
36
+ "test:--extract-response-error": "node tests/spec/extractResponseError/test.js",
34
37
  "test:--enum-names-as-values": "node tests/spec/enumNamesAsValues/test.js",
35
38
  "test:--default-response": "node tests/spec/defaultResponse/test.js",
36
39
  "test:--js": "node tests/spec/js/test.js",
@@ -38,6 +41,7 @@
38
41
  "test:--axios": "node tests/spec/axios/test.js",
39
42
  "test:--axios--single-http-client": "node tests/spec/axiosSingleHttpClient/test.js",
40
43
  "test:--type-suffix--type-prefix": "node tests/spec/typeSuffixPrefix/test.js",
44
+ "test:--cli": "node index.js -p tests/spec/cli/schema.json -o tests/spec/cli -n schema.ts --extract-response-body --extract-response-error --type-prefix Prefix --api-class-name MySuperApi --no-client",
41
45
  "test:partialBaseTemplate": "node tests/spec/partialBaseTemplate/test.js",
42
46
  "test:partialDefaultTemplate": "node tests/spec/partialDefaultTemplate/test.js",
43
47
  "test:--patch": "node tests/spec/patch/test.js"
@@ -48,28 +52,28 @@
48
52
  "main": "src/index.js",
49
53
  "devDependencies": {
50
54
  "@types/axios": "^0.14.0",
51
- "@types/lodash": "^4.14.166",
55
+ "@types/lodash": "^4.14.182",
52
56
  "@types/node": "^15.0.2",
53
- "@types/prettier": "^2.1.6",
54
- "all-contributors-cli": "^6.19.0",
55
- "axios": "^0.21.4",
57
+ "@types/prettier": "^2.7.0",
58
+ "all-contributors-cli": "^6.20.0",
56
59
  "husky": "^4.3.6",
57
60
  "pretty-quick": "^3.1.0"
58
61
  },
59
62
  "dependencies": {
60
- "@types/swagger-schema-official": "2.0.21",
61
- "commander": "^6.2.1",
62
- "cosmiconfig": "^7.0.0",
63
- "eta": "^1.12.1",
64
- "js-yaml": "^4.0.0",
63
+ "axios": "^0.27.2",
64
+ "@types/swagger-schema-official": "2.0.22",
65
+ "commander": "^9.4.0",
66
+ "cosmiconfig": "^7.0.1",
67
+ "eta": "^1.12.3",
68
+ "js-yaml": "^4.1.0",
65
69
  "lodash": "^4.17.21",
66
70
  "make-dir": "^3.1.0",
67
- "nanoid": "^3.1.22",
68
- "node-emoji": "^1.10.0",
69
- "prettier": "^2.2.1",
71
+ "nanoid": "^3.3.4",
72
+ "node-emoji": "^1.11.0",
73
+ "prettier": "^2.7.1",
70
74
  "swagger-schema-official": "2.0.0-bab6bed",
71
- "swagger2openapi": "^7.0.5",
72
- "typescript": "^4.2.4"
75
+ "swagger2openapi": "^7.0.8",
76
+ "typescript": "^4.7.4"
73
77
  },
74
78
  "bin": {
75
79
  "swagger-typescript-api": "index.js",
package/src/config.js CHANGED
@@ -14,6 +14,8 @@ const config = {
14
14
  generateClient: true,
15
15
  /** CLI flag */
16
16
  generateUnionEnums: false,
17
+ /** CLI flag */
18
+ addReadonly: false,
17
19
  enumNamesAsValues: false,
18
20
  /** parsed swagger schema from getSwaggerObject() */
19
21
 
@@ -36,6 +38,8 @@ const config = {
36
38
  disableProxy: false,
37
39
  extractRequestParams: false,
38
40
  extractRequestBody: false,
41
+ extractResponseBody: false,
42
+ extractResponseError: false,
39
43
  fileNames: {
40
44
  dataContracts: "data-contracts",
41
45
  routeTypes: "route-types",
@@ -87,6 +91,8 @@ const config = {
87
91
  typeSuffix: "",
88
92
  patch: false,
89
93
  componentTypeNameResolver: new NameResolver([]),
94
+ /** name of the main exported class */
95
+ apiClassName: "Api",
90
96
  };
91
97
 
92
98
  /** needs to use data everywhere in project */
package/src/index.js CHANGED
@@ -40,10 +40,13 @@ module.exports = {
40
40
  generateClient = config.generateClient,
41
41
  httpClientType = config.httpClientType,
42
42
  generateUnionEnums = config.generateUnionEnums,
43
+ addReadonly = config.addReadonly,
43
44
  moduleNameIndex = config.moduleNameIndex,
44
45
  moduleNameFirstTag = config.moduleNameFirstTag,
45
46
  extractRequestParams = config.extractRequestParams,
46
47
  extractRequestBody = config.extractRequestBody,
48
+ extractResponseBody = config.extractResponseBody,
49
+ extractResponseError = config.extractResponseError,
47
50
  defaultResponseType = config.defaultResponseType,
48
51
  unwrapResponseData = config.unwrapResponseData,
49
52
  disableThrowOnError = config.disableThrowOnError,
@@ -60,6 +63,8 @@ module.exports = {
60
63
  typePrefix = config.typePrefix,
61
64
  typeSuffix = config.typeSuffix,
62
65
  patch = config.patch,
66
+ authorizationToken,
67
+ apiClassName = config.apiClassName,
63
68
  }) =>
64
69
  new Promise((resolve, reject) => {
65
70
  addToConfig({
@@ -70,12 +75,15 @@ module.exports = {
70
75
  generateResponses,
71
76
  templates,
72
77
  generateUnionEnums,
78
+ addReadonly,
73
79
  moduleNameIndex,
74
80
  moduleNameFirstTag,
75
81
  prettierOptions,
76
82
  modular,
77
83
  extractRequestParams,
78
84
  extractRequestBody,
85
+ extractResponseBody,
86
+ extractResponseError,
79
87
  hooks: _.merge(config.hooks, rawHooks || {}),
80
88
  enumNamesAsValues,
81
89
  disableStrictSSL,
@@ -92,10 +100,11 @@ module.exports = {
92
100
  typePrefix,
93
101
  typeSuffix,
94
102
  patch,
103
+ apiClassName,
95
104
  });
96
105
  (spec
97
106
  ? convertSwaggerObject(spec, { patch })
98
- : getSwaggerObject(input, url, disableStrictSSL, disableProxy, { patch })
107
+ : getSwaggerObject(input, url, disableStrictSSL, disableProxy, authorizationToken, { patch })
99
108
  )
100
109
  .then(({ usageSchema, originalSchema }) => {
101
110
  const templatePaths = getTemplatePaths(config);
@@ -120,9 +129,7 @@ module.exports = {
120
129
 
121
130
  const componentsMap = createComponentsMap(components);
122
131
 
123
- const componentSchemasNames = filterComponentsMap(componentsMap, "schemas").map(
124
- (c) => c.typeName,
125
- );
132
+ const componentSchemasNames = filterComponentsMap(componentsMap, "schemas").map((c) => c.typeName);
126
133
 
127
134
  addToConfig({
128
135
  componentTypeNameResolver: new ComponentTypeNameResolver(componentSchemasNames),
@@ -146,29 +153,32 @@ module.exports = {
146
153
 
147
154
  const usageComponentSchemas = filterComponentsMap(componentsMap, "schemas");
148
155
  const sortByProperty = (o1, o2, propertyName) => {
149
- if(o1[propertyName] > o2[propertyName]) {
156
+ if (o1[propertyName] > o2[propertyName]) {
150
157
  return 1;
151
158
  }
152
- if(o1[propertyName] < o2[propertyName]) {
159
+ if (o1[propertyName] < o2[propertyName]) {
153
160
  return -1;
154
161
  }
155
162
  return 0;
156
- }
157
- const sortByTypeName = (o1, o2) => sortByProperty(o1, o2, 'typeName');
163
+ };
164
+ const sortByTypeName = (o1, o2) => sortByProperty(o1, o2, "typeName");
158
165
 
159
- const sortByName = (o1, o2) => sortByProperty(o1, o2, 'name');
166
+ const sortByName = (o1, o2) => sortByProperty(o1, o2, "name");
160
167
 
161
168
  const sortSchemas = (schemas) => {
162
- if(config.sortTypes) {
169
+ if (config.sortTypes) {
163
170
  return schemas.sort(sortByTypeName).map((schema) => {
164
- if(schema.rawTypeData?.properties) {
171
+ if (schema.rawTypeData?.properties) {
165
172
  return {
166
173
  ...schema,
167
174
  rawTypeData: {
168
175
  ...schema.rawTypeData,
169
- '$parsed': {...schema.rawTypeData['$parsed'], content: schema.rawTypeData['$parsed'].content.sort(sortByName)}
170
- }
171
- }
176
+ $parsed: {
177
+ ...schema.rawTypeData["$parsed"],
178
+ content: schema.rawTypeData["$parsed"].content.sort(sortByName),
179
+ },
180
+ },
181
+ };
172
182
  }
173
183
  return schema;
174
184
  });
package/src/routeNames.js CHANGED
@@ -13,19 +13,15 @@ const getRouteName = (routeInfo) => {
13
13
  config,
14
14
  });
15
15
 
16
- const routeName =
17
- config.hooks.onFormatRouteName(routeInfo, routeNameFromTemplate) || routeNameFromTemplate;
16
+ const routeName = config.hooks.onFormatRouteName(routeInfo, routeNameFromTemplate) || routeNameFromTemplate;
18
17
 
19
18
  const duplicateIdentifier = `${moduleName}|${routeName}`;
20
19
 
21
20
  if (routeNameDuplicatesMap.has(duplicateIdentifier)) {
22
- routeNameDuplicatesMap.set(
23
- duplicateIdentifier,
24
- routeNameDuplicatesMap.get(duplicateIdentifier) + 1,
25
- );
21
+ routeNameDuplicatesMap.set(duplicateIdentifier, routeNameDuplicatesMap.get(duplicateIdentifier) + 1);
26
22
 
27
23
  logger.warn(
28
- `Module "${moduleName}" already have method "${routeName}()"`,
24
+ `Module "${moduleName}" already has method "${routeName}()"`,
29
25
  `\nThis method has been renamed to "${
30
26
  routeName + routeNameDuplicatesMap.get(duplicateIdentifier)
31
27
  }()" to solve conflict names.`,
package/src/routes.js CHANGED
@@ -1,12 +1,5 @@
1
1
  const _ = require("lodash");
2
- const {
3
- types,
4
- parseSchema,
5
- getType,
6
- getRefType,
7
- getInlineParseContent,
8
- checkAndAddNull,
9
- } = require("./schema");
2
+ const { types, parseSchema, getType, getRefType, getInlineParseContent, checkAndAddNull } = require("./schema");
10
3
  const { formatModelName } = require("./modelNames");
11
4
  const {
12
5
  DEFAULT_BODY_ARG_NAME,
@@ -19,7 +12,7 @@ const {
19
12
  } = require("./constants");
20
13
  const { formatDescription, classNameCase } = require("./common");
21
14
  const { config } = require("./config");
22
- const { nanoid } = require("nanoid");
15
+ const { generateId } = require("./utils/id");
23
16
  const { getRouteName } = require("./routeNames");
24
17
  const { createComponent } = require("./components");
25
18
  const { logger } = require("./logger");
@@ -47,26 +40,15 @@ const getSchemaFromRequestType = (requestInfo) => {
47
40
  return null;
48
41
  };
49
42
 
50
- const getTypeFromRequestInfo = ({
51
- requestInfo,
52
- parsedSchemas,
53
- operationId,
54
- defaultType,
55
- typeName,
56
- }) => {
43
+ const getTypeFromRequestInfo = ({ requestInfo, parsedSchemas, operationId, defaultType, typeName }) => {
57
44
  // TODO: make more flexible pick schema without content type
58
45
  const schema = getSchemaFromRequestType(requestInfo);
59
46
  const refTypeInfo = getRefType(requestInfo);
60
47
 
61
48
  if (schema) {
62
49
  const content = getInlineParseContent(schema, typeName);
63
- const foundedSchemaByName = _.find(
64
- parsedSchemas,
65
- (parsedSchema) => formatModelName(parsedSchema.name) === content,
66
- );
67
- const foundSchemaByContent = _.find(parsedSchemas, (parsedSchema) =>
68
- _.isEqual(parsedSchema.content, content),
69
- );
50
+ const foundedSchemaByName = _.find(parsedSchemas, (parsedSchema) => formatModelName(parsedSchema.name) === content);
51
+ const foundSchemaByContent = _.find(parsedSchemas, (parsedSchema) => _.isEqual(parsedSchema.content, content));
70
52
 
71
53
  const foundSchema = foundedSchemaByName || foundSchemaByContent;
72
54
 
@@ -88,10 +70,7 @@ const getTypeFromRequestInfo = ({
88
70
  return formatModelName(refTypeInfo.typeName);
89
71
  case "responses":
90
72
  case "requestBodies":
91
- return getInlineParseContent(
92
- getSchemaFromRequestType(refTypeInfo.rawTypeData),
93
- refTypeInfo.typeName || null,
94
- );
73
+ return getInlineParseContent(getSchemaFromRequestType(refTypeInfo.rawTypeData), refTypeInfo.typeName || null);
95
74
  default:
96
75
  return getInlineParseContent(refTypeInfo.rawTypeData, refTypeInfo.typeName || null);
97
76
  }
@@ -344,9 +323,7 @@ const createRequestParamsSchema = ({
344
323
  if (fixedSchema) return fixedSchema;
345
324
 
346
325
  if (extractRequestParams) {
347
- const typeName = config.componentTypeNameResolver.resolve([
348
- classNameCase(`${routeName.usage} Params`),
349
- ]);
326
+ const typeName = config.componentTypeNameResolver.resolve([classNameCase(`${routeName.usage} Params`)]);
350
327
 
351
328
  return createComponent("schemas", typeName, { ...schema });
352
329
  }
@@ -358,9 +335,7 @@ const getContentTypes = (requestInfo, extraContentTypes) =>
358
335
  _.uniq(
359
336
  _.compact([
360
337
  ...(extraContentTypes || []),
361
- ..._.flatten(
362
- _.map(requestInfo, (requestInfoData) => requestInfoData && _.keys(requestInfoData.content)),
363
- ),
338
+ ..._.flatten(_.map(requestInfo, (requestInfoData) => requestInfoData && _.keys(requestInfoData.content))),
364
339
  ]),
365
340
  );
366
341
 
@@ -400,10 +375,7 @@ const getRequestBodyInfo = (routeInfo, routeParams, parsedSchemas, routeName) =>
400
375
  let schema = null;
401
376
  let type = null;
402
377
 
403
- const contentTypes = getContentTypes(
404
- [requestBody],
405
- [...(consumes || []), routeInfo["x-contentType"]],
406
- );
378
+ const contentTypes = getContentTypes([requestBody], [...(consumes || []), routeInfo["x-contentType"]]);
407
379
  let contentKind = getContentKind(contentTypes);
408
380
 
409
381
  let typeName = null;
@@ -454,8 +426,7 @@ const getRequestBodyInfo = (routeInfo, routeParams, parsedSchemas, routeName) =>
454
426
  contentKind,
455
427
  schema,
456
428
  type,
457
- required:
458
- requestBody && (typeof requestBody.required === "undefined" || !!requestBody.required),
429
+ required: requestBody && (typeof requestBody.required === "undefined" || !!requestBody.required),
459
430
  };
460
431
  };
461
432
 
@@ -472,9 +443,7 @@ const getResponseBodyInfo = (routeInfo, routeParams, parsedSchemas) => {
472
443
  });
473
444
 
474
445
  const successResponse = responseInfos.find((response) => response.isSuccess);
475
- const errorResponses = responseInfos.filter(
476
- (response) => !response.isSuccess && response.type !== TS_KEYWORDS.ANY,
477
- );
446
+ const errorResponses = responseInfos.filter((response) => !response.isSuccess && response.type !== TS_KEYWORDS.ANY);
478
447
 
479
448
  const handleResponseHeaders = (src) => {
480
449
  if (!src) {
@@ -507,24 +476,16 @@ const getResponseBodyInfo = (routeInfo, routeParams, parsedSchemas) => {
507
476
  responseInfos
508
477
  .map(
509
478
  (response) => `{
510
- data: ${response.type}, status: ${response.status}, statusCode: ${
511
- response.status
512
- }, statusText: "${response.description}", ${handleResponseHeaders(
513
- response.headers,
514
- )} config: {} }`,
479
+ data: ${response.type}, status: ${response.status}, statusCode: ${response.status}, statusText: "${
480
+ response.description
481
+ }", ${handleResponseHeaders(response.headers)} config: {} }`,
515
482
  )
516
483
  .join(" | ") || TS_KEYWORDS.ANY,
517
484
  },
518
485
  };
519
486
  };
520
487
 
521
- const parseRoutes = ({
522
- usageSchema,
523
- parsedSchemas,
524
- moduleNameIndex,
525
- moduleNameFirstTag,
526
- extractRequestParams,
527
- }) => {
488
+ const parseRoutes = ({ usageSchema, parsedSchemas, moduleNameIndex, moduleNameFirstTag, extractRequestParams }) => {
528
489
  const { paths, security: globalSecurity } = usageSchema;
529
490
  const pathsEntries = _.entries(paths);
530
491
 
@@ -553,16 +514,13 @@ const parseRoutes = ({
553
514
  } = routeInfo;
554
515
  const { route, pathParams } = parseRoute(rawRoute);
555
516
 
556
- const routeId = nanoid(12);
517
+ const routeId = generateId();
557
518
  const firstTag = tags && tags.length > 0 ? tags[0] : null;
558
519
  const moduleName =
559
520
  moduleNameFirstTag && firstTag
560
521
  ? _.camelCase(firstTag)
561
522
  : _.camelCase(_.compact(_.split(route, "/"))[moduleNameIndex]);
562
- const hasSecurity = !!(
563
- (globalSecurity && globalSecurity.length) ||
564
- (security && security.length)
565
- );
523
+ const hasSecurity = !!((globalSecurity && globalSecurity.length) || (security && security.length));
566
524
 
567
525
  const routeParams = getRouteParams(routeInfo, pathParams);
568
526
 
@@ -599,12 +557,7 @@ const parseRoutes = ({
599
557
 
600
558
  const routeName = getRouteName(rawRouteInfo);
601
559
 
602
- const requestBodyInfo = getRequestBodyInfo(
603
- routeInfo,
604
- routeParams,
605
- parsedSchemas,
606
- routeName,
607
- );
560
+ const requestBodyInfo = getRequestBodyInfo(routeInfo, routeParams, parsedSchemas, routeName);
608
561
 
609
562
  const requestParamsSchema = createRequestParamsSchema({
610
563
  queryParams: routeParams.query,
@@ -614,13 +567,12 @@ const parseRoutes = ({
614
567
  routeName,
615
568
  });
616
569
 
617
- const queryType = routeParams.query.length
618
- ? getInlineParseContent(queryObjectSchema)
619
- : null;
570
+ extractResponseBodyIfItNeeded(routeInfo, responseBodyInfo, routeParams, rawRouteInfo, routeName);
571
+ extractResponseErrorIfItNeeded(routeInfo, responseBodyInfo, routeParams, rawRouteInfo, routeName);
572
+
573
+ const queryType = routeParams.query.length ? getInlineParseContent(queryObjectSchema) : null;
620
574
  const pathType = routeParams.path.length ? getInlineParseContent(pathObjectSchema) : null;
621
- const headersType = routeParams.header.length
622
- ? getInlineParseContent(headersObjectSchema)
623
- : null;
575
+ const headersType = routeParams.header.length ? getInlineParseContent(headersObjectSchema) : null;
624
576
 
625
577
  const nameResolver = new SpecificArgNameResolver(pathArgsNames);
626
578
 
@@ -634,10 +586,7 @@ const parseRoutes = ({
634
586
  : void 0,
635
587
  body: requestBodyInfo.type
636
588
  ? {
637
- name: nameResolver.resolve([
638
- requestBodyInfo.paramName,
639
- ...RESERVED_BODY_ARG_NAMES,
640
- ]),
589
+ name: nameResolver.resolve([requestBodyInfo.paramName, ...RESERVED_BODY_ARG_NAMES]),
641
590
  optional: !requestBodyInfo.required,
642
591
  type: requestBodyInfo.type,
643
592
  }
@@ -764,10 +713,7 @@ const groupRoutes = (routes) => {
764
713
  if (
765
714
  packRoutes.length > 1 &&
766
715
  usageName !== originalName &&
767
- !_.some(
768
- packRoutes,
769
- ({ routeName, id }) => id !== route.id && originalName === routeName.original,
770
- )
716
+ !_.some(packRoutes, ({ routeName, id }) => id !== route.id && originalName === routeName.original)
771
717
  ) {
772
718
  return {
773
719
  ...route,
@@ -788,6 +734,72 @@ const groupRoutes = (routes) => {
788
734
  );
789
735
  };
790
736
 
737
+ const extractResponseBodyIfItNeeded = (routeInfo, responseBodyInfo, routeParams, rawRouteInfo, routeName) => {
738
+ if (
739
+ config.extractResponseBody &&
740
+ responseBodyInfo.responses.length &&
741
+ responseBodyInfo.success &&
742
+ responseBodyInfo.success.schema
743
+ ) {
744
+ const typeName = config.componentTypeNameResolver.resolve([
745
+ classNameCase(`${routeName.usage} Data`),
746
+ classNameCase(`${routeName.usage} Result`),
747
+ classNameCase(`${routeName.usage} Output`),
748
+ ]);
749
+
750
+ const idx = responseBodyInfo.responses.indexOf(responseBodyInfo.success.schema);
751
+
752
+ let successResponse = responseBodyInfo.success;
753
+
754
+ if (successResponse.schema && !successResponse.schema.$ref) {
755
+ const schema = getSchemaFromRequestType(successResponse.schema);
756
+ successResponse.schema = createComponent("schemas", typeName, { ...schema });
757
+ successResponse.type = getInlineParseContent(successResponse.schema);
758
+
759
+ if (idx > -1) {
760
+ responseBodyInfo.responses[idx] = successResponse.schema;
761
+ }
762
+ }
763
+ }
764
+ };
765
+
766
+ const extractResponseErrorIfItNeeded = (routeInfo, responseBodyInfo, routeParams, rawRouteInfo, routeName) => {
767
+ if (
768
+ config.extractResponseError &&
769
+ responseBodyInfo.responses.length &&
770
+ responseBodyInfo.error.schemas &&
771
+ responseBodyInfo.error.schemas.length
772
+ ) {
773
+ const typeName = config.componentTypeNameResolver.resolve([
774
+ classNameCase(`${routeName.usage} Error`),
775
+ classNameCase(`${routeName.usage} Fail`),
776
+ classNameCase(`${routeName.usage} Fails`),
777
+ classNameCase(`${routeName.usage} ErrorData`),
778
+ classNameCase(`${routeName.usage} HttpError`),
779
+ classNameCase(`${routeName.usage} BadResponse`),
780
+ ]);
781
+
782
+ const errorSchemas = responseBodyInfo.error.schemas.map(getSchemaFromRequestType).filter(Boolean);
783
+
784
+ if (!errorSchemas.length) return;
785
+
786
+ const schema = parseSchema({
787
+ oneOf: errorSchemas,
788
+ title: errorSchemas
789
+ .map((schema) => schema.title)
790
+ .filter(Boolean)
791
+ .join(" "),
792
+ description: errorSchemas
793
+ .map((schema) => schema.description)
794
+ .filter(Boolean)
795
+ .join("\n"),
796
+ });
797
+ const component = createComponent("schemas", typeName, { ...schema });
798
+ responseBodyInfo.error.schemas = [component];
799
+ responseBodyInfo.error.type = formatModelName(component.typeName);
800
+ }
801
+ };
802
+
791
803
  module.exports = {
792
804
  parseRoutes,
793
805
  groupRoutes,
package/src/schema.js CHANGED
@@ -63,12 +63,7 @@ const getTypeAlias = (rawSchema) => {
63
63
  };
64
64
 
65
65
  const getEnumNames = (schema) => {
66
- return (
67
- schema["x-enumNames"] ||
68
- schema["xEnumNames"] ||
69
- schema["x-enumnames"] ||
70
- schema["x-enum-varnames"]
71
- );
66
+ return schema["x-enumNames"] || schema["xEnumNames"] || schema["x-enumnames"] || schema["x-enum-varnames"];
72
67
  };
73
68
 
74
69
  const getInternalSchemaType = (schema) => {
@@ -137,6 +132,7 @@ const getObjectTypeContent = (schema) => {
137
132
  const nullable = !!(rawTypeData.nullable || property.nullable);
138
133
  const fieldName = isValidName(name) ? name : `"${name}"`;
139
134
  const fieldValue = getInlineParseContent(property);
135
+ const readOnly = property.readOnly;
140
136
 
141
137
  return {
142
138
  $$raw: property,
@@ -147,20 +143,25 @@ const getObjectTypeContent = (schema) => {
147
143
  rawTypeData.description ||
148
144
  _.compact(_.map(rawTypeData[getComplexType(rawTypeData)], "description"))[0] ||
149
145
  "",
146
+ !_.isUndefined(property.deprecated) && `@deprecated`,
150
147
  !_.isUndefined(property.format) && `@format ${property.format}`,
151
148
  !_.isUndefined(property.minimum) && `@min ${property.minimum}`,
152
149
  !_.isUndefined(property.maximum) && `@max ${property.maximum}`,
153
150
  !_.isUndefined(property.pattern) && `@pattern ${property.pattern}`,
154
151
  !_.isUndefined(property.example) &&
155
- `@example ${
156
- _.isObject(property.example) ? JSON.stringify(property.example) : property.example
157
- }`,
152
+ `@example ${_.isObject(property.example) ? JSON.stringify(property.example) : property.example}`,
158
153
  ]).join("\n"),
159
154
  isRequired: required,
160
155
  isNullable: nullable,
161
156
  name: fieldName,
162
157
  value: fieldValue,
163
- field: _.compact([fieldName, !required && "?", ": ", fieldValue]).join(""),
158
+ field: _.compact([
159
+ readOnly && config.addReadonly && "readonly ",
160
+ fieldName,
161
+ !required && "?",
162
+ ": ",
163
+ fieldValue,
164
+ ]).join(""),
164
165
  };
165
166
  });
166
167
 
@@ -179,39 +180,73 @@ const getObjectTypeContent = (schema) => {
179
180
  const complexTypeGetter = (schema) => getInlineParseContent(schema);
180
181
  const filterContents = (contents, types) => _.filter(contents, (type) => !_.includes(types, type));
181
182
 
183
+ const makeAddRequiredToChildSchema = (parentSchema) => (childSchema) => {
184
+ let required = childSchema.required || [];
185
+ let properties = childSchema.properties || {};
186
+
187
+ // Inherit all the required fields from the parent schema that are defined
188
+ // either on the parent schema or on the child schema
189
+ // TODO: any that are defined at grandparents or higher are ignored
190
+ required = required.concat(
191
+ (parentSchema.required || []).filter(
192
+ (key) =>
193
+ !required.includes(key) && (_.keys(properties).includes(key) || _.keys(parentSchema.properties).includes(key)),
194
+ ),
195
+ );
196
+
197
+ // Identify properties that are required in the child schema, but
198
+ // defined only in the parent schema (TODO: this only works one level deep)
199
+ const parentPropertiesRequiredByChild = required.filter(
200
+ (key) => !_.keys(childSchema.properties).includes(key) && _.keys(parentSchema.properties).includes(key),
201
+ );
202
+
203
+ // Add such properties to the child so that they can be overriden and made required
204
+ properties = {
205
+ ...properties,
206
+ ...parentPropertiesRequiredByChild.reduce(
207
+ (additionalProperties, key) => ({
208
+ ...additionalProperties,
209
+ [key]: (parentSchema.properties || {})[key],
210
+ }),
211
+ {},
212
+ ),
213
+ };
214
+
215
+ return _.merge(
216
+ {
217
+ required: required,
218
+ properties: properties,
219
+ },
220
+ childSchema,
221
+ );
222
+ };
223
+
182
224
  const complexSchemaParsers = {
183
225
  [SCHEMA_TYPES.COMPLEX_ONE_OF]: (schema) => {
184
226
  // T1 | T2
185
- const combined = _.map(schema.oneOf, complexTypeGetter);
227
+ const combined = _.map(_.map(schema.oneOf, makeAddRequiredToChildSchema(schema)), complexTypeGetter);
186
228
 
187
229
  return checkAndAddNull(schema, filterContents(combined, [TS_KEYWORDS.ANY]).join(" | "));
188
230
  },
189
231
  [SCHEMA_TYPES.COMPLEX_ALL_OF]: (schema) => {
190
232
  // T1 & T2
191
- const combined = _.map(schema.allOf, complexTypeGetter);
233
+ const combined = _.map(_.map(schema.allOf, makeAddRequiredToChildSchema(schema)), complexTypeGetter);
192
234
  return checkAndAddNull(
193
235
  schema,
194
- filterContents(combined, [...JS_EMPTY_TYPES, ...JS_PRIMITIVE_TYPES, TS_KEYWORDS.ANY]).join(
195
- " & ",
196
- ),
236
+ filterContents(combined, [...JS_EMPTY_TYPES, ...JS_PRIMITIVE_TYPES, TS_KEYWORDS.ANY]).join(" & "),
197
237
  );
198
238
  },
199
239
  [SCHEMA_TYPES.COMPLEX_ANY_OF]: (schema) => {
200
240
  // T1 | T2 | (T1 & T2)
201
- const combined = _.map(schema.anyOf, complexTypeGetter);
202
- const nonEmptyTypesCombined = filterContents(combined, [
203
- ...JS_EMPTY_TYPES,
204
- ...JS_PRIMITIVE_TYPES,
205
- TS_KEYWORDS.ANY,
206
- ]);
241
+ const combined = _.map(_.map(schema.anyOf, makeAddRequiredToChildSchema(schema)), complexTypeGetter);
242
+ const nonEmptyTypesCombined = filterContents(combined, [...JS_EMPTY_TYPES, ...JS_PRIMITIVE_TYPES, TS_KEYWORDS.ANY]);
207
243
  return checkAndAddNull(
208
244
  schema,
209
- `${combined.join(" | ")}` +
210
- (nonEmptyTypesCombined.length > 1 ? ` | (${nonEmptyTypesCombined.join(" & ")})` : ""),
245
+ `${combined.join(" | ")}` + (nonEmptyTypesCombined.length > 1 ? ` | (${nonEmptyTypesCombined.join(" & ")})` : ""),
211
246
  );
212
247
  },
213
248
  // TODO
214
- [SCHEMA_TYPES.COMPLEX_NOT_OF]: (schema) => {
249
+ [SCHEMA_TYPES.COMPLEX_NOT]: (schema) => {
215
250
  // TODO
216
251
  return TS_KEYWORDS.ANY;
217
252
  },
@@ -228,8 +263,7 @@ const getComplexType = (schema) => {
228
263
  };
229
264
 
230
265
  const attachParsedRef = (originalSchema, parsedSchema) => {
231
- const parsedSchemaAfterHook =
232
- config.hooks.onParseSchema(originalSchema, parsedSchema) || parsedSchema;
266
+ const parsedSchemaAfterHook = config.hooks.onParseSchema(originalSchema, parsedSchema) || parsedSchema;
233
267
 
234
268
  if (originalSchema) {
235
269
  originalSchema.$parsed = parsedSchemaAfterHook;
@@ -264,12 +298,7 @@ const schemaParsers = {
264
298
  return {
265
299
  key: formattedKey,
266
300
  type: keyType,
267
- value:
268
- enumValue === null
269
- ? enumValue
270
- : isIntegerOrBooleanEnum
271
- ? `${enumValue}`
272
- : `"${enumValue}"`,
301
+ value: enumValue === null ? enumValue : isIntegerOrBooleanEnum ? `${enumValue}` : `"${enumValue}"`,
273
302
  };
274
303
  });
275
304
  } else {
@@ -291,9 +320,7 @@ const schemaParsers = {
291
320
  type: SCHEMA_TYPES.ENUM,
292
321
  keyType: keyType,
293
322
  typeIdentifier:
294
- config.generateUnionEnums || (!enumNames && isIntegerOrBooleanEnum)
295
- ? TS_KEYWORDS.TYPE
296
- : TS_KEYWORDS.ENUM,
323
+ config.generateUnionEnums || (!enumNames && isIntegerOrBooleanEnum) ? TS_KEYWORDS.TYPE : TS_KEYWORDS.ENUM,
297
324
  name: typeName,
298
325
  description: formatDescription(schema.description),
299
326
  content,
@@ -332,8 +359,7 @@ const schemaParsers = {
332
359
  content:
333
360
  _.compact([
334
361
  complexSchemaContent && `(${complexSchemaContent})`,
335
- getInternalSchemaType(simpleSchema) === TS_KEYWORDS.OBJECT &&
336
- getInlineParseContent(simpleSchema),
362
+ getInternalSchemaType(simpleSchema) === TS_KEYWORDS.OBJECT && getInlineParseContent(simpleSchema),
337
363
  ]).join(" & ") || TS_KEYWORDS.ANY,
338
364
  });
339
365
  },
@@ -401,10 +427,7 @@ const parseSchema = (rawSchema, typeName, formattersMap) => {
401
427
  parsedSchema = schemaParsers[schemaType](fixedRawSchema, typeName);
402
428
  }
403
429
 
404
- return (
405
- (formattersMap && formattersMap[schemaType] && formattersMap[schemaType](parsedSchema)) ||
406
- parsedSchema
407
- );
430
+ return (formattersMap && formattersMap[schemaType] && formattersMap[schemaType](parsedSchema)) || parsedSchema;
408
431
  };
409
432
 
410
433
  const parseSchemas = (components) =>
@@ -413,8 +436,7 @@ const parseSchemas = (components) =>
413
436
  const getInlineParseContent = (rawTypeData, typeName = null) =>
414
437
  parseSchema(rawTypeData, typeName, inlineExtraFormatters).content;
415
438
 
416
- const getParseContent = (rawTypeData, typeName = null) =>
417
- parseSchema(rawTypeData, typeName).content;
439
+ const getParseContent = (rawTypeData, typeName = null) => parseSchema(rawTypeData, typeName).content;
418
440
 
419
441
  module.exports = {
420
442
  types,
package/src/swagger.js CHANGED
@@ -17,7 +17,7 @@ const parseSwaggerFile = (file) => {
17
17
  }
18
18
  };
19
19
 
20
- const getSwaggerFile = (pathToSwagger, urlToSwagger, disableStrictSSL, disableProxy) =>
20
+ const getSwaggerFile = (pathToSwagger, urlToSwagger, disableStrictSSL, disableProxy, authorizationToken) =>
21
21
  new Promise((resolve, reject) => {
22
22
  if (pathIsExist(pathToSwagger)) {
23
23
  logger.log(`try to get swagger by path "${pathToSwagger}"`);
@@ -33,15 +33,21 @@ const getSwaggerFile = (pathToSwagger, urlToSwagger, disableStrictSSL, disablePr
33
33
  });
34
34
  }
35
35
  //
36
+ if (authorizationToken) {
37
+ axiosOptions.headers = {
38
+ Authorization: authorizationToken,
39
+ };
40
+ }
41
+ //
36
42
  if (disableProxy) axiosOptions.proxy = false;
37
43
  //
38
44
  axios
39
45
  .get(urlToSwagger, axiosOptions)
40
46
  .then((res) => resolve(res.data))
41
- .catch(() => {
47
+ .catch((error) => {
42
48
  const message = `error while getting swagger by URL ${urlToSwagger}`;
43
49
 
44
- logger.error(message);
50
+ logger.error(message, "response" in error ? error.response : error);
45
51
 
46
52
  reject(message);
47
53
  });
@@ -53,9 +59,10 @@ const getSwaggerObject = (
53
59
  urlToSwagger,
54
60
  disableStrictSSL,
55
61
  disableProxy,
62
+ authorizationToken,
56
63
  converterOptions,
57
64
  ) =>
58
- getSwaggerFile(pathToSwagger, urlToSwagger, disableStrictSSL, disableProxy).then((file) =>
65
+ getSwaggerFile(pathToSwagger, urlToSwagger, disableStrictSSL, disableProxy, authorizationToken).then((file) =>
59
66
  convertSwaggerObject(parseSwaggerFile(file), converterOptions),
60
67
  );
61
68
 
@@ -0,0 +1,9 @@
1
+ const { customAlphabet } = require("nanoid");
2
+
3
+ const ALPHABET = "abcdefghijklmnopqrstuvwxyz0123456789";
4
+
5
+ const generateId = customAlphabet(ALPHABET, 12);
6
+
7
+ module.exports = {
8
+ generateId,
9
+ };
@@ -1,7 +1,7 @@
1
1
  <%
2
2
  const { modelTypes, utils } = it;
3
3
  const { formatDescription, require, _ } = utils;
4
-
4
+
5
5
 
6
6
  const dataContractTemplates = {
7
7
  enum: (contract) => {
@@ -20,6 +20,7 @@
20
20
 
21
21
  return _.compact([
22
22
  contract.description && formatDescription(contract.description),
23
+ contract.typeData.deprecated === true && '@deprecated',
23
24
  !_.isUndefined(contract.typeData.format) && `@format ${contract.typeData.format}`,
24
25
  !_.isUndefined(contract.typeData.minimum) && `@min ${contract.typeData.minimum}`,
25
26
  !_.isUndefined(contract.typeData.maximum) && `@max ${contract.typeData.maximum}`,
@@ -2,7 +2,7 @@
2
2
  const { apiConfig, generateResponses, config } = it;
3
3
  %>
4
4
 
5
- import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse, ResponseType } from "axios";
5
+ import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse, ResponseType, HeadersDefaults } from "axios";
6
6
 
7
7
  export type QueryParamsType = Record<string | number, any>;
8
8
 
@@ -53,20 +53,44 @@ export class HttpClient<SecurityDataType = unknown> {
53
53
  this.securityData = data
54
54
  }
55
55
 
56
- private mergeRequestParams(params1: AxiosRequestConfig, params2?: AxiosRequestConfig): AxiosRequestConfig {
57
- return {
58
- ...this.instance.defaults,
59
- ...params1,
60
- ...(params2 || {}),
61
- headers: {
62
- ...(this.instance.defaults.headers || {}),
63
- ...(params1.headers || {}),
64
- ...((params2 && params2.headers) || {}),
65
- },
66
- };
56
+ protected mergeRequestParams(params1: AxiosRequestConfig, params2?: AxiosRequestConfig): AxiosRequestConfig {
57
+ const method = params1.method || (params2 && params2.method)
58
+
59
+ return {
60
+ ...this.instance.defaults,
61
+ ...params1,
62
+ ...(params2 || {}),
63
+ headers: {
64
+ ...((method && this.instance.defaults.headers[method.toLowerCase() as keyof HeadersDefaults]) || {}),
65
+ ...(params1.headers || {}),
66
+ ...((params2 && params2.headers) || {}),
67
+ },
68
+ };
67
69
  }
68
70
 
69
- private createFormData(input: Record<string, unknown>): FormData {
71
+ protected stringifyFormItem(formItem: unknown) {
72
+ if (typeof formItem === "object" && formItem !== null) {
73
+ return JSON.stringify(formItem);
74
+ } else {
75
+ return `${formItem}`;
76
+ }
77
+ }
78
+
79
+ protected createFormData(input: Record<string, unknown>): FormData {
80
+ return Object.keys(input || {}).reduce((formData, key) => {
81
+ const property = input[key];
82
+ const propertyContent: Iterable<any> = (property instanceof Array) ? property : [property]
83
+
84
+ for (const formItem of propertyContent) {
85
+ const isFileType = formItem instanceof Blob || formItem instanceof File;
86
+ formData.append(
87
+ key,
88
+ isFileType ? formItem : this.stringifyFormItem(formItem)
89
+ );
90
+ }
91
+
92
+ return formData;
93
+ }, new FormData());
70
94
  return Object.keys(input || {}).reduce((formData, key) => {
71
95
  const property = input[key];
72
96
  formData.append(
@@ -96,13 +120,9 @@ export class HttpClient<SecurityDataType = unknown> {
96
120
  <% } %>
97
121
  const secureParams = ((typeof secure === 'boolean' ? secure : this.secure) && this.securityWorker && (await this.securityWorker(this.securityData))) || {};
98
122
  const requestParams = this.mergeRequestParams(params, secureParams);
99
- const responseFormat = (format && this.format) || void 0;
123
+ const responseFormat = (format || this.format) || undefined;
100
124
 
101
125
  if (type === ContentType.FormData && body && body !== null && typeof body === "object") {
102
- requestParams.headers.common = { Accept: "*/*" };
103
- requestParams.headers.post = {};
104
- requestParams.headers.put = {};
105
-
106
126
  body = this.createFormData(body as Record<string, unknown>);
107
127
  }
108
128
 
@@ -68,17 +68,17 @@ export class HttpClient<SecurityDataType = unknown> {
68
68
  public setSecurityData = (data: SecurityDataType | null) => {
69
69
  this.securityData = data;
70
70
  }
71
-
72
- private encodeQueryParam(key: string, value: any) {
71
+
72
+ protected encodeQueryParam(key: string, value: any) {
73
73
  const encodedKey = encodeURIComponent(key);
74
74
  return `${encodedKey}=${encodeURIComponent(typeof value === "number" ? value : `${value}`)}`;
75
75
  }
76
76
 
77
- private addQueryParam(query: QueryParamsType, key: string) {
77
+ protected addQueryParam(query: QueryParamsType, key: string) {
78
78
  return this.encodeQueryParam(key, query[key]);
79
79
  }
80
80
 
81
- private addArrayQueryParam(query: QueryParamsType, key: string) {
81
+ protected addArrayQueryParam(query: QueryParamsType, key: string) {
82
82
  const value = query[key];
83
83
  return value.map((v: any) => this.encodeQueryParam(key, v)).join("&");
84
84
  }
@@ -118,7 +118,7 @@ export class HttpClient<SecurityDataType = unknown> {
118
118
  [ContentType.UrlEncoded]: (input: any) => this.toQueryString(input),
119
119
  }
120
120
 
121
- private mergeRequestParams(params1: RequestParams, params2?: RequestParams): RequestParams {
121
+ protected mergeRequestParams(params1: RequestParams, params2?: RequestParams): RequestParams {
122
122
  return {
123
123
  ...this.baseApiParams,
124
124
  ...params1,
@@ -131,7 +131,7 @@ export class HttpClient<SecurityDataType = unknown> {
131
131
  };
132
132
  }
133
133
 
134
- private createAbortSignal = (cancelToken: CancelToken): AbortSignal | undefined => {
134
+ protected createAbortSignal = (cancelToken: CancelToken): AbortSignal | undefined => {
135
135
  if (this.abortControllers.has(cancelToken)) {
136
136
  const abortController = this.abortControllers.get(cancelToken);
137
137
  if (abortController) {
@@ -183,7 +183,7 @@ export class HttpClient<SecurityDataType = unknown> {
183
183
  ...(type && type !== ContentType.FormData ? { "Content-Type": type } : {}),
184
184
  ...(requestParams.headers || {}),
185
185
  },
186
- signal: cancelToken ? this.createAbortSignal(cancelToken) : void 0,
186
+ signal: cancelToken ? this.createAbortSignal(cancelToken) : requestParams.signal,
187
187
  body: typeof body === "undefined" || body === null ? null : payloadFormatter(body),
188
188
  }
189
189
  ).then(async (response) => {
@@ -36,7 +36,7 @@ const descriptionLines = _.compact([
36
36
  <% }) %>
37
37
  */
38
38
  <% } %>
39
- export class Api<SecurityDataType extends unknown><% if (!config.singleHttpClient) { %> extends HttpClient<SecurityDataType> <% } %> {
39
+ export class <%~ config.apiClassName %><SecurityDataType extends unknown><% if (!config.singleHttpClient) { %> extends HttpClient<SecurityDataType> <% } %> {
40
40
 
41
41
  <% if(config.singleHttpClient) { %>
42
42
  http: HttpClient<SecurityDataType>;