swagger-typescript-api 13.0.0-experimental-1 → 13.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +22 -12
  3. package/cli/constants.js +3 -3
  4. package/cli/execute.js +52 -31
  5. package/cli/index.d.ts +1 -2
  6. package/cli/index.js +18 -17
  7. package/cli/operations/display-help.js +51 -29
  8. package/cli/parse-args.js +3 -3
  9. package/cli/process-option.js +28 -20
  10. package/index.d.ts +113 -8
  11. package/index.js +158 -135
  12. package/package.json +35 -30
  13. package/src/code-formatter.js +28 -13
  14. package/src/code-gen-process.js +357 -259
  15. package/src/commands/generate-templates/configuration.js +2 -2
  16. package/src/commands/generate-templates/index.js +1 -2
  17. package/src/commands/generate-templates/templates-gen-process.js +62 -35
  18. package/src/component-type-name-resolver.js +44 -0
  19. package/src/configuration.js +167 -95
  20. package/src/constants.js +28 -22
  21. package/src/index.js +3 -4
  22. package/src/schema-components-map.js +39 -23
  23. package/src/schema-parser/base-schema-parsers/array.js +43 -0
  24. package/src/schema-parser/base-schema-parsers/complex.js +51 -0
  25. package/src/schema-parser/base-schema-parsers/discriminator.js +301 -0
  26. package/src/schema-parser/base-schema-parsers/enum.js +158 -0
  27. package/src/schema-parser/base-schema-parsers/object.js +105 -0
  28. package/src/schema-parser/base-schema-parsers/primitive.js +63 -0
  29. package/src/schema-parser/complex-schema-parsers/all-of.js +26 -0
  30. package/src/schema-parser/complex-schema-parsers/any-of.js +34 -0
  31. package/src/schema-parser/complex-schema-parsers/not.js +9 -0
  32. package/src/schema-parser/complex-schema-parsers/one-of.js +27 -0
  33. package/src/schema-parser/mono-schema-parser.js +48 -0
  34. package/src/schema-parser/schema-formatters.js +69 -60
  35. package/src/schema-parser/schema-parser-fabric.js +131 -0
  36. package/src/schema-parser/schema-parser.js +208 -427
  37. package/src/schema-parser/schema-utils.js +123 -58
  38. package/src/schema-parser/util/enum-key-resolver.js +26 -0
  39. package/src/schema-routes/schema-routes.js +1225 -0
  40. package/src/schema-routes/util/specific-arg-name-resolver.js +26 -0
  41. package/src/schema-walker.js +93 -0
  42. package/src/swagger-schema-resolver.js +61 -28
  43. package/src/templates-worker.js +240 -0
  44. package/src/translators/javascript.js +83 -0
  45. package/src/translators/translator.js +35 -0
  46. package/src/type-name-formatter.js +33 -18
  47. package/src/util/file-system.js +30 -14
  48. package/src/util/id.js +2 -2
  49. package/src/util/internal-case.js +1 -1
  50. package/src/util/logger.js +46 -20
  51. package/src/util/name-resolver.js +52 -60
  52. package/src/util/object-assign.js +7 -3
  53. package/src/util/pascal-case.js +1 -1
  54. package/src/util/request.js +5 -5
  55. package/src/util/sort-by-property.js +17 -0
  56. package/templates/README.md +17 -17
  57. package/templates/base/README.md +7 -7
  58. package/templates/base/data-contract-jsdoc.ejs +37 -37
  59. package/templates/base/data-contracts.ejs +40 -27
  60. package/templates/base/enum-data-contract.ejs +12 -12
  61. package/templates/base/http-client.ejs +3 -3
  62. package/templates/base/http-clients/axios-http-client.ejs +139 -138
  63. package/templates/base/http-clients/fetch-http-client.ejs +224 -224
  64. package/templates/base/interface-data-contract.ejs +10 -10
  65. package/templates/base/object-field-jsdoc.ejs +28 -28
  66. package/templates/base/route-docs.ejs +30 -30
  67. package/templates/base/route-name.ejs +42 -42
  68. package/templates/base/route-type.ejs +22 -21
  69. package/templates/base/type-data-contract.ejs +15 -15
  70. package/templates/default/README.md +6 -6
  71. package/templates/default/api.ejs +69 -68
  72. package/templates/default/procedure-call.ejs +100 -100
  73. package/templates/default/route-types.ejs +32 -32
  74. package/templates/modular/README.md +6 -6
  75. package/templates/modular/api.ejs +28 -28
  76. package/templates/modular/procedure-call.ejs +100 -100
  77. package/templates/modular/route-types.ejs +18 -18
  78. package/src/schema-parser/schema-processor.js +0 -79
  79. package/src/schema-parser/schema-routes.js +0 -950
  80. package/src/templates.js +0 -182
  81. package/src/translators/JavaScript.js +0 -60
@@ -1,37 +1,37 @@
1
- <%
2
- const { data, utils } = it;
3
- const { formatDescription, require, _ } = utils;
4
-
5
- const stringify = (value) => _.isObject(value) ? JSON.stringify(value) : _.isString(value) ? `"${value}"` : value
6
-
7
- const jsDocLines = _.compact([
8
- data.title,
9
- data.description && formatDescription(data.description),
10
- !_.isUndefined(data.deprecated) && data.deprecated && '@deprecated',
11
- !_.isUndefined(data.format) && `@format ${data.format}`,
12
- !_.isUndefined(data.minimum) && `@min ${data.minimum}`,
13
- !_.isUndefined(data.multipleOf) && `@multipleOf ${data.multipleOf}`,
14
- !_.isUndefined(data.exclusiveMinimum) && `@exclusiveMin ${data.exclusiveMinimum}`,
15
- !_.isUndefined(data.maximum) && `@max ${data.maximum}`,
16
- !_.isUndefined(data.minLength) && `@minLength ${data.minLength}`,
17
- !_.isUndefined(data.maxLength) && `@maxLength ${data.maxLength}`,
18
- !_.isUndefined(data.exclusiveMaximum) && `@exclusiveMax ${data.exclusiveMaximum}`,
19
- !_.isUndefined(data.maxItems) && `@maxItems ${data.maxItems}`,
20
- !_.isUndefined(data.minItems) && `@minItems ${data.minItems}`,
21
- !_.isUndefined(data.uniqueItems) && `@uniqueItems ${data.uniqueItems}`,
22
- !_.isUndefined(data.default) && `@default ${stringify(data.default)}`,
23
- !_.isUndefined(data.pattern) && `@pattern ${data.pattern}`,
24
- !_.isUndefined(data.example) && `@example ${stringify(data.example)}`
25
- ]).join('\n').split('\n');
26
- %>
27
- <% if (jsDocLines.every(_.isEmpty)) { %>
28
- <% } else if (jsDocLines.length === 1) { %>
29
- /** <%~ jsDocLines[0] %> */
30
- <% } else if (jsDocLines.length) { %>
31
- /**
32
- <% for (jsDocLine of jsDocLines) { %>
33
- * <%~ jsDocLine %>
34
-
35
- <% } %>
36
- */
37
- <% } %>
1
+ <%
2
+ const { data, utils } = it;
3
+ const { formatDescription, require, _ } = utils;
4
+
5
+ const stringify = (value) => _.isObject(value) ? JSON.stringify(value) : _.isString(value) ? `"${value}"` : value
6
+
7
+ const jsDocLines = _.compact([
8
+ data.title,
9
+ data.description && formatDescription(data.description),
10
+ !_.isUndefined(data.deprecated) && data.deprecated && '@deprecated',
11
+ !_.isUndefined(data.format) && `@format ${data.format}`,
12
+ !_.isUndefined(data.minimum) && `@min ${data.minimum}`,
13
+ !_.isUndefined(data.multipleOf) && `@multipleOf ${data.multipleOf}`,
14
+ !_.isUndefined(data.exclusiveMinimum) && `@exclusiveMin ${data.exclusiveMinimum}`,
15
+ !_.isUndefined(data.maximum) && `@max ${data.maximum}`,
16
+ !_.isUndefined(data.minLength) && `@minLength ${data.minLength}`,
17
+ !_.isUndefined(data.maxLength) && `@maxLength ${data.maxLength}`,
18
+ !_.isUndefined(data.exclusiveMaximum) && `@exclusiveMax ${data.exclusiveMaximum}`,
19
+ !_.isUndefined(data.maxItems) && `@maxItems ${data.maxItems}`,
20
+ !_.isUndefined(data.minItems) && `@minItems ${data.minItems}`,
21
+ !_.isUndefined(data.uniqueItems) && `@uniqueItems ${data.uniqueItems}`,
22
+ !_.isUndefined(data.default) && `@default ${stringify(data.default)}`,
23
+ !_.isUndefined(data.pattern) && `@pattern ${data.pattern}`,
24
+ !_.isUndefined(data.example) && `@example ${stringify(data.example)}`
25
+ ]).join('\n').split('\n');
26
+ %>
27
+ <% if (jsDocLines.every(_.isEmpty)) { %>
28
+ <% } else if (jsDocLines.length === 1) { %>
29
+ /** <%~ jsDocLines[0] %> */
30
+ <% } else if (jsDocLines.length) { %>
31
+ /**
32
+ <% for (jsDocLine of jsDocLines) { %>
33
+ * <%~ jsDocLine %>
34
+
35
+ <% } %>
36
+ */
37
+ <% } %>
@@ -1,27 +1,40 @@
1
- <%
2
- const { modelTypes, utils, config } = it;
3
- const { formatDescription, require, _, Ts } = utils;
4
-
5
- const dataContractTemplates = {
6
- enum: (contract) => {
7
- return `enum ${contract.name} {\r\n${contract.content} \r\n }`;
8
- },
9
- interface: (contract) => {
10
- return `interface ${contract.name} {\r\n${contract.content}}`;
11
- },
12
- type: (contract) => {
13
- return `type ${contract.name} = ${contract.content}`;
14
- },
15
- }
16
- %>
17
-
18
- <% if (config.internalTemplateOptions.addUtilRequiredKeysType) { %>
19
- type <%~ config.Ts.CodeGenKeyword.UtilRequiredKeys %><T, K extends keyof T> = Omit<T, K> & Required<Pick<T, K>>
20
- <% } %>
21
-
22
- <% for await (const contract of modelTypes) { %>
23
-
24
- <%~ await includeFile('@base/data-contract-jsdoc.ejs', { ...it, data: { ...contract, ...contract.typeData } }) %>
25
- export <%~ (dataContractTemplates[contract.typeIdentifier] || dataContractTemplates.type)(contract) %>
26
-
27
- <% } %>
1
+ <%
2
+ const { modelTypes, utils, config } = it;
3
+ const { formatDescription, require, _, Ts } = utils;
4
+
5
+
6
+ const buildGenerics = (contract) => {
7
+ if (!contract.genericArgs || !contract.genericArgs.length) return '';
8
+
9
+ return '<' + contract.genericArgs.map(({ name, default: defaultType, extends: extendsType }) => {
10
+ return [
11
+ name,
12
+ extendsType && `extends ${extendsType}`,
13
+ defaultType && `= ${defaultType}`,
14
+ ].join('')
15
+ }).join(',') + '>'
16
+ }
17
+
18
+ const dataContractTemplates = {
19
+ enum: (contract) => {
20
+ return `enum ${contract.name} {\r\n${contract.content} \r\n }`;
21
+ },
22
+ interface: (contract) => {
23
+ return `interface ${contract.name}${buildGenerics(contract)} {\r\n${contract.content}}`;
24
+ },
25
+ type: (contract) => {
26
+ return `type ${contract.name}${buildGenerics(contract)} = ${contract.content}`;
27
+ },
28
+ }
29
+ %>
30
+
31
+ <% if (config.internalTemplateOptions.addUtilRequiredKeysType) { %>
32
+ type <%~ config.Ts.CodeGenKeyword.UtilRequiredKeys %><T, K extends keyof T> = Omit<T, K> & Required<Pick<T, K>>
33
+ <% } %>
34
+
35
+ <% for (const contract of modelTypes) { %>
36
+ <%~ includeFile('@base/data-contract-jsdoc.ejs', { ...it, data: { ...contract, ...contract.typeData } }) %>
37
+ <%~ contract.internal ? '' : 'export'%> <%~ (dataContractTemplates[contract.typeIdentifier] || dataContractTemplates.type)(contract) %>
38
+
39
+
40
+ <% } %>
@@ -1,12 +1,12 @@
1
- <%
2
- const { contract, utils, config } = it;
3
- const { formatDescription, require, _ } = utils;
4
- const { name, $content } = contract;
5
- %>
6
- <% if (config.generateUnionEnums) { %>
7
- export type <%~ name %> = <%~ _.map($content, ({ value }) => value).join(" | ") %>
8
- <% } else { %>
9
- export enum <%~ name %> {
10
- <%~ _.map($content, ({ key, value }) => `${key} = ${value}`).join(",\n") %>
11
- }
12
- <% } %>
1
+ <%
2
+ const { contract, utils, config } = it;
3
+ const { formatDescription, require, _ } = utils;
4
+ const { name, $content } = contract;
5
+ %>
6
+ <% if (config.generateUnionEnums) { %>
7
+ export type <%~ name %> = <%~ _.map($content, ({ value }) => value).join(" | ") %>
8
+ <% } else { %>
9
+ export enum <%~ name %> {
10
+ <%~ _.map($content, ({ key, value }) => `${key} = ${value}`).join(",\n") %>
11
+ }
12
+ <% } %>
@@ -1,3 +1,3 @@
1
- <% const { config } = it; %>
2
- <% /* https://github.com/acacode/swagger-typescript-api/tree/next/templates/base/http-clients/ */ %>
3
- <%~ await includeFile(`@base/http-clients/${config.httpClientType}-http-client`, it) %>
1
+ <% const { config } = it; %>
2
+ <% /* https://github.com/acacode/swagger-typescript-api/tree/next/templates/base/http-clients/ */ %>
3
+ <%~ includeFile(`@base/http-clients/${config.httpClientType}-http-client`, it) %>
@@ -1,138 +1,139 @@
1
- <%
2
- const { apiConfig, generateResponses, config } = it;
3
- %>
4
-
5
- import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse, ResponseType, HeadersDefaults } from "axios";
6
-
7
- export type QueryParamsType = Record<string | number, any>;
8
-
9
- export interface FullRequestParams extends Omit<AxiosRequestConfig, "data" | "params" | "url" | "responseType"> {
10
- /** set parameter to `true` for call `securityWorker` for this request */
11
- secure?: boolean;
12
- /** request path */
13
- path: string;
14
- /** content type of request body */
15
- type?: ContentType;
16
- /** query params */
17
- query?: QueryParamsType;
18
- /** format of response (i.e. response.json() -> format: "json") */
19
- format?: ResponseType;
20
- /** request body */
21
- body?: unknown;
22
- }
23
-
24
- export type RequestParams = Omit<FullRequestParams, "body" | "method" | "query" | "path">;
25
-
26
- export interface ApiConfig<SecurityDataType = unknown> extends Omit<AxiosRequestConfig, "data" | "cancelToken"> {
27
- securityWorker?: (securityData: SecurityDataType | null) => Promise<AxiosRequestConfig | void> | AxiosRequestConfig | void;
28
- secure?: boolean;
29
- format?: ResponseType;
30
- }
31
-
32
- export enum ContentType {
33
- Json = "application/json",
34
- FormData = "multipart/form-data",
35
- UrlEncoded = "application/x-www-form-urlencoded",
36
- Text = "text/plain",
37
- }
38
-
39
- export class HttpClient<SecurityDataType = unknown> {
40
- public instance: AxiosInstance;
41
- private securityData: SecurityDataType | null = null;
42
- private securityWorker?: ApiConfig<SecurityDataType>["securityWorker"];
43
- private secure?: boolean;
44
- private format?: ResponseType;
45
-
46
- constructor({ securityWorker, secure, format, ...axiosConfig }: ApiConfig<SecurityDataType> = {}) {
47
- this.instance = axios.create({ ...axiosConfig, baseURL: axiosConfig.baseURL || "<%~ apiConfig.baseUrl %>" })
48
- this.secure = secure;
49
- this.format = format;
50
- this.securityWorker = securityWorker;
51
- }
52
-
53
- public setSecurityData = (data: SecurityDataType | null) => {
54
- this.securityData = data
55
- }
56
-
57
- protected mergeRequestParams(params1: AxiosRequestConfig, params2?: AxiosRequestConfig): AxiosRequestConfig {
58
- const method = params1.method || (params2 && params2.method)
59
-
60
- return {
61
- ...this.instance.defaults,
62
- ...params1,
63
- ...(params2 || {}),
64
- headers: {
65
- ...((method && this.instance.defaults.headers[method.toLowerCase() as keyof HeadersDefaults]) || {}),
66
- ...(params1.headers || {}),
67
- ...((params2 && params2.headers) || {}),
68
- },
69
- };
70
- }
71
-
72
- protected stringifyFormItem(formItem: unknown) {
73
- if (typeof formItem === "object" && formItem !== null) {
74
- return JSON.stringify(formItem);
75
- } else {
76
- return `${formItem}`;
77
- }
78
- }
79
-
80
- protected createFormData(input: Record<string, unknown>): FormData {
81
- return Object.keys(input || {}).reduce((formData, key) => {
82
- const property = input[key];
83
- const propertyContent: any[] = (property instanceof Array) ? property : [property]
84
-
85
- for (const formItem of propertyContent) {
86
- const isFileType = formItem instanceof Blob || formItem instanceof File;
87
- formData.append(
88
- key,
89
- isFileType ? formItem : this.stringifyFormItem(formItem)
90
- );
91
- }
92
-
93
- return formData;
94
- }, new FormData());
95
- }
96
-
97
- public request = async <T = any, _E = any>({
98
- secure,
99
- path,
100
- type,
101
- query,
102
- format,
103
- body,
104
- ...params
105
- <% if (config.unwrapResponseData) { %>
106
- }: FullRequestParams): Promise<T> => {
107
- <% } else { %>
108
- }: FullRequestParams): Promise<AxiosResponse<T>> => {
109
- <% } %>
110
- const secureParams = ((typeof secure === 'boolean' ? secure : this.secure) && this.securityWorker && (await this.securityWorker(this.securityData))) || {};
111
- const requestParams = this.mergeRequestParams(params, secureParams);
112
- const responseFormat = (format || this.format) || undefined;
113
-
114
- if (type === ContentType.FormData && body && body !== null && typeof body === "object") {
115
- body = this.createFormData(body as Record<string, unknown>);
116
- }
117
-
118
- if (type === ContentType.Text && body && body !== null && typeof body !== "string") {
119
- body = JSON.stringify(body);
120
- }
121
-
122
- return this.instance.request({
123
- ...requestParams,
124
- headers: {
125
- ...(requestParams.headers || {}),
126
- ...(type && type !== ContentType.FormData ? { "Content-Type": type } : {}),
127
- },
128
- params: query,
129
- responseType: responseFormat,
130
- data: body,
131
- url: path,
132
- <% if (config.unwrapResponseData) { %>
133
- }).then(response => response.data);
134
- <% } else { %>
135
- });
136
- <% } %>
137
- };
138
- }
1
+ <%
2
+ const { apiConfig, generateResponses, config } = it;
3
+ %>
4
+
5
+ import type { AxiosInstance, AxiosRequestConfig, HeadersDefaults, ResponseType, AxiosResponse } from "axios";
6
+ import axios from "axios";
7
+
8
+ export type QueryParamsType = Record<string | number, any>;
9
+
10
+ export interface FullRequestParams extends Omit<AxiosRequestConfig, "data" | "params" | "url" | "responseType"> {
11
+ /** set parameter to `true` for call `securityWorker` for this request */
12
+ secure?: boolean;
13
+ /** request path */
14
+ path: string;
15
+ /** content type of request body */
16
+ type?: ContentType;
17
+ /** query params */
18
+ query?: QueryParamsType;
19
+ /** format of response (i.e. response.json() -> format: "json") */
20
+ format?: ResponseType;
21
+ /** request body */
22
+ body?: unknown;
23
+ }
24
+
25
+ export type RequestParams = Omit<FullRequestParams, "body" | "method" | "query" | "path">;
26
+
27
+ export interface ApiConfig<SecurityDataType = unknown> extends Omit<AxiosRequestConfig, "data" | "cancelToken"> {
28
+ securityWorker?: (securityData: SecurityDataType | null) => Promise<AxiosRequestConfig | void> | AxiosRequestConfig | void;
29
+ secure?: boolean;
30
+ format?: ResponseType;
31
+ }
32
+
33
+ export enum ContentType {
34
+ Json = "application/json",
35
+ FormData = "multipart/form-data",
36
+ UrlEncoded = "application/x-www-form-urlencoded",
37
+ Text = "text/plain",
38
+ }
39
+
40
+ export class HttpClient<SecurityDataType = unknown> {
41
+ public instance: AxiosInstance;
42
+ private securityData: SecurityDataType | null = null;
43
+ private securityWorker?: ApiConfig<SecurityDataType>["securityWorker"];
44
+ private secure?: boolean;
45
+ private format?: ResponseType;
46
+
47
+ constructor({ securityWorker, secure, format, ...axiosConfig }: ApiConfig<SecurityDataType> = {}) {
48
+ this.instance = axios.create({ ...axiosConfig, baseURL: axiosConfig.baseURL || "<%~ apiConfig.baseUrl %>" })
49
+ this.secure = secure;
50
+ this.format = format;
51
+ this.securityWorker = securityWorker;
52
+ }
53
+
54
+ public setSecurityData = (data: SecurityDataType | null) => {
55
+ this.securityData = data
56
+ }
57
+
58
+ protected mergeRequestParams(params1: AxiosRequestConfig, params2?: AxiosRequestConfig): AxiosRequestConfig {
59
+ const method = params1.method || (params2 && params2.method)
60
+
61
+ return {
62
+ ...this.instance.defaults,
63
+ ...params1,
64
+ ...(params2 || {}),
65
+ headers: {
66
+ ...((method && this.instance.defaults.headers[method.toLowerCase() as keyof HeadersDefaults]) || {}),
67
+ ...(params1.headers || {}),
68
+ ...((params2 && params2.headers) || {}),
69
+ },
70
+ };
71
+ }
72
+
73
+ protected stringifyFormItem(formItem: unknown) {
74
+ if (typeof formItem === "object" && formItem !== null) {
75
+ return JSON.stringify(formItem);
76
+ } else {
77
+ return `${formItem}`;
78
+ }
79
+ }
80
+
81
+ protected createFormData(input: Record<string, unknown>): FormData {
82
+ return Object.keys(input || {}).reduce((formData, key) => {
83
+ const property = input[key];
84
+ const propertyContent: any[] = (property instanceof Array) ? property : [property]
85
+
86
+ for (const formItem of propertyContent) {
87
+ const isFileType = formItem instanceof Blob || formItem instanceof File;
88
+ formData.append(
89
+ key,
90
+ isFileType ? formItem : this.stringifyFormItem(formItem)
91
+ );
92
+ }
93
+
94
+ return formData;
95
+ }, new FormData());
96
+ }
97
+
98
+ public request = async <T = any, _E = any>({
99
+ secure,
100
+ path,
101
+ type,
102
+ query,
103
+ format,
104
+ body,
105
+ ...params
106
+ <% if (config.unwrapResponseData) { %>
107
+ }: FullRequestParams): Promise<T> => {
108
+ <% } else { %>
109
+ }: FullRequestParams): Promise<AxiosResponse<T>> => {
110
+ <% } %>
111
+ const secureParams = ((typeof secure === 'boolean' ? secure : this.secure) && this.securityWorker && (await this.securityWorker(this.securityData))) || {};
112
+ const requestParams = this.mergeRequestParams(params, secureParams);
113
+ const responseFormat = (format || this.format) || undefined;
114
+
115
+ if (type === ContentType.FormData && body && body !== null && typeof body === "object") {
116
+ body = this.createFormData(body as Record<string, unknown>);
117
+ }
118
+
119
+ if (type === ContentType.Text && body && body !== null && typeof body !== "string") {
120
+ body = JSON.stringify(body);
121
+ }
122
+
123
+ return this.instance.request({
124
+ ...requestParams,
125
+ headers: {
126
+ ...(requestParams.headers || {}),
127
+ ...(type && type !== ContentType.FormData ? { "Content-Type": type } : {}),
128
+ },
129
+ params: query,
130
+ responseType: responseFormat,
131
+ data: body,
132
+ url: path,
133
+ <% if (config.unwrapResponseData) { %>
134
+ }).then(response => response.data);
135
+ <% } else { %>
136
+ });
137
+ <% } %>
138
+ };
139
+ }