swagger-typescript-api 11.1.3 → 12.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/README.md CHANGED
@@ -70,11 +70,12 @@ Options:
70
70
  --type-prefix <string> data contract name prefix (default: "")
71
71
  --type-suffix <string> data contract name suffix (default: "")
72
72
  --clean-output clean output folder before generate api. WARNING: May cause data loss (default: false)
73
- --api-class-name <string> name of the api class
73
+ --api-class-name <string> name of the api class (default: "Api")
74
74
  --patch fix up small errors in the swagger source definition (default: false)
75
75
  --debug additional information about processes inside this tool (default: false)
76
76
  --another-array-type generate array types as Array<Type> (by default Type[]) (default: false)
77
77
  --sort-types sort fields and types (default: false)
78
+ --extract-enums extract all enums from inline interface\type content to typescript enum construction (default: false)
78
79
  -h, --help display help for command
79
80
 
80
81
  Commands:
@@ -138,9 +139,20 @@ generateApi({
138
139
  generateUnionEnums: false,
139
140
  typePrefix: '',
140
141
  typeSuffix: '',
142
+ enumKeyPrefix: '',
143
+ enumKeySuffix: '',
141
144
  addReadonly: false,
145
+ extractingOptions: {
146
+ requestBodySuffix: ["Payload", "Body", "Input"],
147
+ requestParamsSuffix: ["Params"],
148
+ responseBodySuffix: ["Data", "Result", "Output"],
149
+ responseErrorSuffix: ["Error", "Fail", "Fails", "ErrorData", "HttpError", "BadResponse"],
150
+ },
151
+ /** allow to generate extra files based with this extra templates, see more below */
142
152
  extraTemplates: [],
143
- anotherArrayType: false,
153
+ anotherArrayType: false,
154
+ fixInvalidTypeNamePrefix: "Type",
155
+ fixInvalidEnumKeyPrefix: "Value",
144
156
  codeGenConstructs: (constructs) => ({
145
157
  ...constructs,
146
158
  RecordType: (key, value) => `MyRecord<key, value>`
@@ -157,8 +169,9 @@ generateApi({
157
169
  onCreateRoute: (routeData) => {},
158
170
  onCreateRouteName: (routeNameInfo, rawRouteInfo) => {},
159
171
  onFormatRouteName: (routeInfo, templateRouteName) => {},
160
- onFormatTypeName: (typeName, rawTypeName) => {},
172
+ onFormatTypeName: (typeName, rawTypeName, schemaType) => {},
161
173
  onInit: (configuration) => {},
174
+ onPreParseSchema: (originalSchema, typeName, schemaType) => {},
162
175
  onParseSchema: (originalSchema, parsedSchema) => {},
163
176
  onPrepareConfig: (currentConfiguration) => {},
164
177
  }
@@ -239,8 +252,13 @@ with `--module-name-index 0` Api class will have one property `api`
239
252
  When we change it to `--module-name-index 1` then Api class have two properties `fruits` and `vegetables`
240
253
 
241
254
  ### **`--module-name-first-tag`**
242
- This option will group your API operations based on their first tag - mirroring how the Swagger UI groups displayed operations
255
+ This option will group your API operations based on their first tag - mirroring how the Swagger UI groups displayed operations
243
256
 
257
+ ### `extraTemplates` (NodeJS option)
258
+ type `(Record<string, any> & { name: string, path: string })[]`
259
+ This thing allow you to generate extra ts\js files based on extra templates (one extra template for one ts\js file)
260
+ [Example here](https://github.com/acacode/swagger-typescript-api/tree/next/tests/spec/extra-templates)
261
+
244
262
 
245
263
  ## `generate-templates` command
246
264
  This command allows you to generate source templates which using with option `--templates`
@@ -427,7 +445,7 @@ generateApi({
427
445
  },
428
446
  array: (schema, parser) => {
429
447
  const content = parser.getInlineParseContent(schema.items);
430
- return parser.checkAndAddNull(schema, `(${content})[]`);
448
+ return parser.safeAddNullToType(schema, `(${content})[]`);
431
449
  },
432
450
  })
433
451
  })
package/cli/index.js CHANGED
File without changes
package/index.d.ts CHANGED
@@ -106,7 +106,7 @@ interface GenerateApiParamsBase {
106
106
  /**
107
107
  * default type for empty response schema (default: "void")
108
108
  */
109
- defaultResponseType?: boolean;
109
+ defaultResponseType?: string;
110
110
  /**
111
111
  * Ability to send HttpClient instance to Api constructor
112
112
  */
@@ -136,6 +136,25 @@ interface GenerateApiParamsBase {
136
136
  primitiveTypeConstructs?: (struct: PrimitiveTypeStruct) => Partial<PrimitiveTypeStruct>;
137
137
 
138
138
  codeGenConstructs?: (struct: CodeGenConstruct) => Partial<CodeGenConstruct>;
139
+
140
+ /** extract all enums from nested types\interfaces to `enum` construction */
141
+ extractEnums?: boolean;
142
+ /** prefix string value needed to fix invalid type names (default: 'Type') */
143
+ fixInvalidTypeNamePrefix?: string;
144
+ /** prefix string value needed to fix invalid enum keys (default: 'Value') */
145
+ fixInvalidEnumKeyPrefix?: string;
146
+ /** prefix string value for enum keys */
147
+ enumKeyPrefix?: string;
148
+ /** suffix string value for enum keys */
149
+ enumKeySuffix?: string;
150
+ /** prefix string value for type names */
151
+ typePrefix?: string;
152
+ /** suffix string value for type names */
153
+ typeSuffix?: string;
154
+ /** extra configuration for extracting type names operations */
155
+ extractingOptions?: Partial<ExtractingOptions>;
156
+ /** configuration for fetching swagger schema requests */
157
+ requestOptions?: null | Partial<import("node-fetch").RequestInit>;
139
158
  }
140
159
 
141
160
  type CodeGenConstruct = {
@@ -212,9 +231,39 @@ interface GenerateApiParamsFromSpecLiteral extends GenerateApiParamsBase {
212
231
 
213
232
  export type GenerateApiParams = GenerateApiParamsFromPath | GenerateApiParamsFromUrl | GenerateApiParamsFromSpecLiteral;
214
233
 
234
+ type BuildRouteParam = {
235
+ /** {bar} */
236
+ $match: string;
237
+ name: string;
238
+ required: boolean;
239
+ type: "string";
240
+ description: string;
241
+ schema: {
242
+ type: string;
243
+ };
244
+ in: "path" | "query";
245
+ };
246
+
247
+ type BuildRoutePath = {
248
+ /** /foo/{bar}/baz */
249
+ originalRoute: string;
250
+ /** /foo/${bar}/baz */
251
+ route: string;
252
+ pathParams: BuildRouteParam[];
253
+ queryParams: BuildRouteParam[];
254
+ };
255
+
215
256
  export interface Hooks {
257
+ /** calls before parse\process route path */
258
+ onPreBuildRoutePath: (routePath: string) => string | void;
259
+ /** calls after parse\process route path */
260
+ onBuildRoutePath: (data: BuildRoutePath) => BuildRoutePath | void;
261
+ /** calls before insert path param name into string path interpolation */
262
+ onInsertPathParam: (paramName: string, index: number, arr: BuildRouteParam[], resultRoute: string) => string | void;
216
263
  /** calls after parse schema component */
217
264
  onCreateComponent: (component: SchemaComponent) => SchemaComponent | void;
265
+ /** calls before parse any kind of schema */
266
+ onPreParseSchema: (originalSchema: any, typeName: string, schemaType: string) => any;
218
267
  /** calls after parse any kind of schema */
219
268
  onParseSchema: (originalSchema: any, parsedSchema: any) => any | void;
220
269
  /** calls after parse route (return type: customized route (ParsedRoute), nothing change (void), false (ignore this route)) */
@@ -228,7 +277,7 @@ export interface Hooks {
228
277
  /** customize request params (path params, query params) */
229
278
  onCreateRequestParams?: (rawType: SchemaComponent["rawTypeData"]) => SchemaComponent["rawTypeData"] | void;
230
279
  /** customize name of model type */
231
- onFormatTypeName?: (typeName: string, rawTypeName?: string) => string | void;
280
+ onFormatTypeName?: (typeName: string, rawTypeName?: string, schemaType?: "type-name" | "enum-key") => string | void;
232
281
  /** customize name of route (operationId), you can do it with using onCreateRouteName too */
233
282
  onFormatRouteName?: (routeInfo: RawRouteInfo, templateRouteName: string) => string | void;
234
283
  }
@@ -376,6 +425,17 @@ export enum SCHEMA_TYPES {
376
425
 
377
426
  type MAIN_SCHEMA_TYPES = SCHEMA_TYPES.PRIMITIVE | SCHEMA_TYPES.OBJECT | SCHEMA_TYPES.ENUM;
378
427
 
428
+ type ExtractingOptions = {
429
+ requestBodySuffix: string[];
430
+ responseBodySuffix: string[];
431
+ responseErrorSuffix: string[];
432
+ requestParamsSuffix: string[];
433
+ requestBodyNameResolver: (name: string, reservedNames: string) => string | undefined;
434
+ responseBodyNameResolver: (name: string, reservedNames: string) => string | undefined;
435
+ responseErrorNameResolver: (name: string, reservedNames: string) => string | undefined;
436
+ requestParamsNameResolver: (name: string, reservedNames: string) => string | undefined;
437
+ };
438
+
379
439
  export interface GenerateApiConfiguration {
380
440
  apiConfig: {
381
441
  baseUrl: string;
@@ -411,6 +471,8 @@ export interface GenerateApiConfiguration {
411
471
  singleHttpClient: boolean;
412
472
  typePrefix: string;
413
473
  typeSuffix: string;
474
+ enumKeyPrefix: string;
475
+ enumKeySuffix: string;
414
476
  patch: boolean;
415
477
  cleanOutput: boolean;
416
478
  debug: boolean;
@@ -420,7 +482,10 @@ export interface GenerateApiConfiguration {
420
482
  addReadonly: boolean;
421
483
  extractResponseBody: boolean;
422
484
  extractResponseError: boolean;
423
- defaultResponseType: boolean;
485
+ extractEnums: boolean;
486
+ fixInvalidTypeNamePrefix: string;
487
+ fixInvalidEnumKeyPrefix: string;
488
+ defaultResponseType: string;
424
489
  toJS: boolean;
425
490
  disableThrowOnError: boolean;
426
491
  silent: boolean;
@@ -452,6 +517,7 @@ export interface GenerateApiConfiguration {
452
517
  routeNameDuplicatesMap: Map<string, string>;
453
518
  apiClassName: string;
454
519
  requestOptions?: import("node-fetch").RequestInit;
520
+ extractingOptions: ExtractingOptions;
455
521
  };
456
522
  modelTypes: ModelType[];
457
523
  rawModelTypes: SchemaComponent[];
@@ -466,6 +532,7 @@ export interface GenerateApiConfiguration {
466
532
  routes: ParsedRoute[];
467
533
  }[];
468
534
  };
535
+ requestOptions?: null | Partial<import("node-fetch").RequestInit>;
469
536
  utils: {
470
537
  formatDescription: (description: string, inline?: boolean) => string;
471
538
  internalCase: (value: string) => string;
package/index.js CHANGED
@@ -37,7 +37,7 @@ const program = cli({
37
37
  {
38
38
  flags: "-n, --name <string>",
39
39
  description: "name of output typescript api file",
40
- default: `${codeGenBaseConfig.apiClassName}.ts`,
40
+ default: codeGenBaseConfig.fileName,
41
41
  },
42
42
  {
43
43
  flags: "-t, --templates <string>",
@@ -202,6 +202,11 @@ const program = cli({
202
202
  description: "sort fields and types",
203
203
  default: codeGenBaseConfig.sortTypes,
204
204
  },
205
+ {
206
+ flags: "--extract-enums",
207
+ description: "extract all enums from inline interface\\type content to typescript enum construction",
208
+ default: codeGenBaseConfig.extractEnums,
209
+ },
205
210
  ],
206
211
  });
207
212
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "swagger-typescript-api",
3
- "version": "11.1.3",
3
+ "version": "12.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",
@@ -56,7 +56,10 @@
56
56
  "test:nullableRefTest2.0": "node tests/spec/nullable-2.0/test.js",
57
57
  "test:additionalProperties2.0": "node tests/spec/additional-properties-2.0/test.js",
58
58
  "test:enums2.0": "node tests/spec/enums-2.0/test.js",
59
- "test:another-query-params": "node tests/spec/another-query-params/test.js"
59
+ "test:another-query-params": "node tests/spec/another-query-params/test.js",
60
+ "test:on-insert-path-param": "node tests/spec/on-insert-path-param/test.js",
61
+ "test:extra-templates": "node tests/spec/extra-templates/test.js",
62
+ "test:extract-enums": "node tests/spec/extract-enums/test.js"
60
63
  },
61
64
  "author": "acacode",
62
65
  "license": "MIT",
@@ -81,6 +81,7 @@ class CodeGenProcess {
81
81
  this.templates,
82
82
  this.typeName,
83
83
  );
84
+ this.config.componentTypeNameResolver.logger = this.logger;
84
85
  }
85
86
 
86
87
  async start() {
@@ -169,9 +170,11 @@ class CodeGenProcess {
169
170
 
170
171
  if (this.fileSystem.pathIsExist(this.config.output)) {
171
172
  if (this.config.cleanOutput) {
173
+ this.logger.debug(`cleaning dir ${this.config.output}`);
172
174
  this.fileSystem.cleanDir(this.config.output);
173
175
  }
174
176
  } else {
177
+ this.logger.debug(`path ${this.config.output} is not exist. creating dir by this path`);
175
178
  this.fileSystem.createDir(this.config.output);
176
179
  }
177
180
 
@@ -233,8 +236,9 @@ class CodeGenProcess {
233
236
  getParseContent: this.schemaParser.getParseContent,
234
237
  getComponentByRef: this.schemaComponentMap.get,
235
238
  parseSchema: this.schemaParser.parseSchema,
236
- checkAndAddNull: this.schemaParser.checkAndAddNull,
237
- isNeedToAddNull: this.schemaParser.isNeedToAddNull,
239
+ checkAndAddNull: this.schemaParser.schemaUtils.safeAddNullToType,
240
+ safeAddNullToType: this.schemaParser.schemaUtils.safeAddNullToType,
241
+ isNeedToAddNull: this.schemaParser.schemaUtils.isNullMissingInType,
238
242
  inlineExtraFormatters: this.schemaParser.schemaFormatters.inline,
239
243
  formatters: this.schemaParser.schemaFormatters.base,
240
244
  formatModelName: this.typeName.format,
@@ -397,15 +401,11 @@ class CodeGenProcess {
397
401
  if (configuration.translateToJavaScript) {
398
402
  const { sourceContent, declarationContent } = translateToJS(`${fixedFileName}${ts.Extension.Ts}`, content);
399
403
 
400
- if (this.config.debug) {
401
- console.info("generating output for", `${fixedFileName}${ts.Extension.Js}`);
402
- console.info(sourceContent);
403
- }
404
+ this.logger.debug("generating output for", `${fixedFileName}${ts.Extension.Js}`);
405
+ this.logger.debug(sourceContent);
404
406
 
405
- if (this.config.debug) {
406
- console.info("generating output for", `${fixedFileName}${ts.Extension.Dts}`);
407
- console.info(declarationContent);
408
- }
407
+ this.logger.debug("generating output for", `${fixedFileName}${ts.Extension.Js}`);
408
+ this.logger.debug(declarationContent);
409
409
 
410
410
  return {
411
411
  name: `${fixedFileName}${ts.Extension.Js}`,
@@ -417,10 +417,8 @@ class CodeGenProcess {
417
417
  };
418
418
  }
419
419
 
420
- if (this.config.debug) {
421
- console.info("generating output for", `${fixedFileName}${ts.Extension.Ts}`);
422
- console.info(content);
423
- }
420
+ this.logger.debug("generating output for", `${fixedFileName}${ts.Extension.Js}`);
421
+ this.logger.debug(content);
424
422
 
425
423
  return {
426
424
  name: `${fixedFileName}${ts.Extension.Ts}`,
@@ -72,6 +72,7 @@ class CodeGenConfig {
72
72
  extractRequestBody = false;
73
73
  extractResponseBody = false;
74
74
  extractResponseError = false;
75
+ extractEnums = false;
75
76
  fileNames = {
76
77
  dataContracts: "data-contracts",
77
78
  routeTypes: "route-types",
@@ -81,14 +82,18 @@ class CodeGenConfig {
81
82
  routeNameDuplicatesMap = new Map();
82
83
  prettierOptions = { ...CONSTANTS.PRETTIER_OPTIONS };
83
84
  hooks = {
85
+ onPreBuildRoutePath: (routePath) => void 0,
86
+ onBuildRoutePath: (routeData) => void 0,
87
+ onInsertPathParam: (pathParam) => void 0,
84
88
  onCreateComponent: (schema) => schema,
89
+ onPreParseSchema: (originalSchema, typeName, schemaType) => void 0,
85
90
  onParseSchema: (originalSchema, parsedSchema) => parsedSchema,
86
91
  onCreateRoute: (routeData) => routeData,
87
92
  onInit: (config) => config,
88
93
  onPrepareConfig: (apiConfig) => apiConfig,
89
94
  onCreateRequestParams: (rawType) => {},
90
95
  onCreateRouteName: () => {},
91
- onFormatTypeName: (typeName, rawTypeName) => {},
96
+ onFormatTypeName: (typeName, rawTypeName, schemaType) => {},
92
97
  onFormatRouteName: (routeInfo, templateRouteName) => {},
93
98
  };
94
99
  defaultResponseType;
@@ -126,8 +131,10 @@ class CodeGenConfig {
126
131
  silent = false;
127
132
  typePrefix = "";
128
133
  typeSuffix = "";
134
+ enumKeyPrefix = "";
135
+ enumKeySuffix = "";
129
136
  patch = false;
130
- componentTypeNameResolver = new ComponentTypeNameResolver([]);
137
+ componentTypeNameResolver = new ComponentTypeNameResolver(null, []);
131
138
  /** name of the main exported class */
132
139
  apiClassName = "Api";
133
140
  debug = false;
@@ -142,15 +149,25 @@ class CodeGenConfig {
142
149
  url = "";
143
150
  cleanOutput = false;
144
151
  spec = null;
145
- fileName = "";
152
+ fileName = "Api.ts";
146
153
  authorizationToken = void 0;
147
154
  requestOptions = null;
148
155
 
149
156
  jsPrimitiveTypes = [];
150
157
  jsEmptyTypes = [];
158
+ fixInvalidTypeNamePrefix = "Type";
159
+ fixInvalidEnumKeyPrefix = "Value";
151
160
 
152
161
  successResponseStatusRange = [200, 299];
153
162
 
163
+ /** @type {ExtractingOptions} */
164
+ extractingOptions = {
165
+ requestBodySuffix: ["Payload", "Body", "Input"],
166
+ requestParamsSuffix: ["Params"],
167
+ responseBodySuffix: ["Data", "Result", "Output"],
168
+ responseErrorSuffix: ["Error", "Fail", "Fails", "ErrorData", "HttpError", "BadResponse"],
169
+ };
170
+
154
171
  Ts = {
155
172
  Keyword: _.cloneDeep(TsKeyword),
156
173
  CodeGenKeyword: _.cloneDeep(TsCodeGenKeyword),
@@ -235,6 +252,12 @@ class CodeGenConfig {
235
252
  TypeWithGeneric: (typeName, genericArgs) => {
236
253
  return `${typeName}${genericArgs.length ? `<${genericArgs.join(",")}>` : ""}`;
237
254
  },
255
+ /**
256
+ * [$A1, $A2, ...$AN]
257
+ */
258
+ Tuple: (values) => {
259
+ return `[${values.join(", ")}]`;
260
+ },
238
261
  };
239
262
 
240
263
  /**
@@ -273,7 +296,7 @@ class CodeGenConfig {
273
296
  },
274
297
  array: ({ items, ...schemaPart }, parser) => {
275
298
  const content = parser.getInlineParseContent(items);
276
- return parser.checkAndAddNull(schemaPart, this.Ts.ArrayType(content));
299
+ return parser.schemaUtils.safeAddNullToType(schemaPart, this.Ts.ArrayType(content));
277
300
  },
278
301
  };
279
302
 
package/src/index.js CHANGED
File without changes
@@ -28,10 +28,7 @@ class SchemaFormatters {
28
28
 
29
29
  base = {
30
30
  [SCHEMA_TYPES.ENUM]: (parsedSchema) => {
31
- const isNumberEnum = _.some(parsedSchema.content, (content) => typeof content.key === "number");
32
- const formatAsUnionType = !!(isNumberEnum || this.config.generateUnionEnums);
33
-
34
- if (formatAsUnionType) {
31
+ if (this.config.generateUnionEnums) {
35
32
  return {
36
33
  ...parsedSchema,
37
34
  $content: parsedSchema.content,
@@ -61,19 +58,32 @@ class SchemaFormatters {
61
58
  },
62
59
  };
63
60
  inline = {
61
+ [SCHEMA_TYPES.ENUM]: (parsedSchema) => {
62
+ return {
63
+ ...parsedSchema,
64
+ content: parsedSchema.$ref
65
+ ? parsedSchema.typeName
66
+ : this.config.Ts.UnionType(
67
+ _.compact([
68
+ ..._.map(parsedSchema.content, ({ value }) => `${value}`),
69
+ parsedSchema.nullable && this.config.Ts.Keyword.Null,
70
+ ]),
71
+ ),
72
+ };
73
+ },
64
74
  [SCHEMA_TYPES.OBJECT]: (parsedSchema) => {
65
75
  if (_.isString(parsedSchema.content)) {
66
76
  return {
67
77
  ...parsedSchema,
68
78
  typeIdentifier: this.config.Ts.Keyword.Type,
69
- content: this.schemaParser.checkAndAddNull(parsedSchema.content),
79
+ content: this.schemaParser.schemaUtils.safeAddNullToType(parsedSchema.content),
70
80
  };
71
81
  }
72
82
 
73
83
  return {
74
84
  ...parsedSchema,
75
85
  typeIdentifier: this.config.Ts.Keyword.Type,
76
- content: this.schemaParser.checkAndAddNull(
86
+ content: this.schemaParser.schemaUtils.safeAddNullToType(
77
87
  parsedSchema,
78
88
  parsedSchema.content.length
79
89
  ? this.config.Ts.ObjectWrapper(this.formatObjectContent(parsedSchema.content))
@@ -81,19 +91,16 @@ class SchemaFormatters {
81
91
  ),
82
92
  };
83
93
  },
84
- [SCHEMA_TYPES.ENUM]: (parsedSchema) => {
85
- return {
86
- ...parsedSchema,
87
- content: parsedSchema.$ref
88
- ? parsedSchema.typeName
89
- : this.config.Ts.UnionType(
90
- _.compact([
91
- ..._.map(parsedSchema.content, ({ value }) => `${value}`),
92
- parsedSchema.nullable && this.config.Ts.Keyword.Null,
93
- ]),
94
- ),
95
- };
96
- },
94
+ };
95
+
96
+ /**
97
+ * @param parsedSchema {Record<string, any>}
98
+ * @param formatType {"base" | "inline"}
99
+ */
100
+ formatSchema = (parsedSchema, formatType = "base") => {
101
+ const schemaType = _.get(parsedSchema, ["schemaType"]) || _.get(parsedSchema, ["$parsed", "schemaType"]);
102
+ const formatterFn = _.get(this, [formatType, schemaType]);
103
+ return (formatterFn && formatterFn(parsedSchema)) || parsedSchema;
97
104
  };
98
105
 
99
106
  formatDescription = (description, inline) => {