swagger2api-v3 1.1.8 → 1.1.9

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
@@ -2,12 +2,12 @@
2
2
 
3
3
  English | [中文](./README_CN.md)
4
4
 
5
- A powerful command-line tool for automatically generating TypeScript or JavaScript interface code from OpenAPI 3.0 documentation.
5
+ A powerful command-line tool for automatically generating TypeScript or JavaScript interface code from OpenAPI 3.x / Swagger 3.0 documentation.
6
6
 
7
7
  ## ✨ Features
8
8
 
9
- - 🚀 **Fast Generation** - Quickly generate TypeScript interface code from Swagger JSON
10
- - 📁 **Smart Grouping** - Support automatic file grouping by Swagger tags
9
+ - 🚀 **Fast Generation** - Quickly generate TypeScript interface code from OpenAPI/Swagger 3.0 JSON
10
+ - 📁 **Smart Grouping** - Support automatic file grouping by document tags
11
11
  - 📝 **Detailed Comments** - Automatically generate detailed comments including descriptions, parameters, and return values
12
12
  - 🎨 **Code Formatting** - Support custom formatting commands
13
13
  - ⚙️ **Environment Adaptation** - Automatically detect project environment and generate corresponding configuration files
@@ -75,7 +75,7 @@ npx swagger2api-v3 generate
75
75
  | Option | Type | Default | Description |
76
76
  | ------------------------ | --------------------- | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
77
77
  | `$schema` | string | - | Local JSON Schema path for editor completion. The default points to `node_modules/swagger2api-v3/dist/.swagger2api.schema.json` |
78
- | `input` | string | - | Swagger JSON file path or URL |
78
+ | `input` | string | - | OpenAPI/Swagger 3.0 JSON file path or URL |
79
79
  | `output` | string | `'./src/api'` | Output directory for generated code |
80
80
  | `generator` | string | `'typescript'` | Code generator type. Supports `'typescript'` and `'javascript'`. `'javascript'` outputs `.js` files and skips type file generation |
81
81
  | `groupByTags` | boolean | `true` | Whether to group files by tags |
@@ -35,7 +35,10 @@ var __importStar = (this && this.__importStar) || (function () {
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.CodeGenerator = void 0;
37
37
  const path = __importStar(require("path"));
38
+ const child_process_1 = require("child_process");
39
+ const util_1 = require("util");
38
40
  const utils_1 = require("../utils");
41
+ const execPromise = (0, util_1.promisify)(child_process_1.exec);
39
42
  /**
40
43
  * 代码生成器
41
44
  */
@@ -433,16 +436,18 @@ class CodeGenerator {
433
436
  this.config.options?.generateModels !== false) {
434
437
  exports.push("export * from './types';");
435
438
  }
436
- if (this.config.groupByTags) {
437
- // 按标签导出
438
- for (const tag of groupedApis.keys()) {
439
- const folderName = this.getTagFileName(tag);
440
- exports.push(`export * from './${folderName}';`);
439
+ if (this.config.options?.generateApis !== false) {
440
+ if (this.config.groupByTags) {
441
+ // 按标签导出
442
+ for (const tag of groupedApis.keys()) {
443
+ const folderName = this.getTagFileName(tag);
444
+ exports.push(`export * from './${folderName}';`);
445
+ }
446
+ }
447
+ else {
448
+ // 导出单个API文件
449
+ exports.push("export * from './api';");
441
450
  }
442
- }
443
- else {
444
- // 导出单个API文件
445
- exports.push("export * from './api';");
446
451
  }
447
452
  const content = [this.generateHeader(), '', ...exports, ''].join('\n');
448
453
  const ext = this.config.generator === 'javascript' ? 'js' : 'ts';
@@ -487,9 +492,6 @@ class CodeGenerator {
487
492
  if (!this.config.lint)
488
493
  return;
489
494
  try {
490
- const { exec } = require('child_process');
491
- const util = require('util');
492
- const execPromise = util.promisify(exec);
493
495
  console.log(`🎨 Running lint command: ${this.config.lint} ${this.config.output}`);
494
496
  const result = await execPromise(`${this.config.lint} ${this.config.output}`);
495
497
  if (result.stdout) {
@@ -37,6 +37,14 @@ export declare class SwaggerParser {
37
37
  * @returns 类型信息
38
38
  */
39
39
  private parseTypeDefinition;
40
+ /**
41
+ * 获取枚举成员名称
42
+ * @param schema 枚举 schema
43
+ * @param value 枚举值
44
+ * @param index 枚举值索引
45
+ * @returns 枚举成员名称
46
+ */
47
+ private getEnumMemberName;
40
48
  /**
41
49
  * 解析本地 $ref 引用对象
42
50
  * @param value 可能带有 $ref 的对象
@@ -2,6 +2,15 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.SwaggerParser = void 0;
4
4
  const utils_1 = require("../utils");
5
+ const HTTP_METHODS = [
6
+ 'get',
7
+ 'post',
8
+ 'put',
9
+ 'delete',
10
+ 'patch',
11
+ 'head',
12
+ 'options'
13
+ ];
5
14
  /**
6
15
  * Swagger文档解析器
7
16
  */
@@ -25,16 +34,7 @@ class SwaggerParser {
25
34
  const apis = [];
26
35
  const paths = this.document.paths;
27
36
  for (const [path, pathItem] of Object.entries(paths)) {
28
- const methods = [
29
- 'get',
30
- 'post',
31
- 'put',
32
- 'delete',
33
- 'patch',
34
- 'head',
35
- 'options'
36
- ];
37
- for (const method of methods) {
37
+ for (const method of HTTP_METHODS) {
38
38
  const operation = pathItem[method];
39
39
  if (!operation)
40
40
  continue;
@@ -97,7 +97,7 @@ class SwaggerParser {
97
97
  const responseType = (0, utils_1.getResponseType)(operation.responses, this.getAllSchemas());
98
98
  // 获取请求体类型
99
99
  const bodyParam = allParameters.find((p) => p.in === 'body');
100
- const requestBodyType = bodyParam
100
+ const requestBodyType = bodyParam?.schema
101
101
  ? (0, utils_1.swaggerTypeToTsType)(bodyParam.schema)
102
102
  : undefined;
103
103
  // 解析参数信息
@@ -178,28 +178,14 @@ class SwaggerParser {
178
178
  else if (schema.type === 'array') {
179
179
  // 数组类型 - 生成指向 items 类型的别名(不带 [])
180
180
  // 在引用时会自动添加 []
181
- const itemType = (0, utils_1.swaggerTypeToTsType)(schema.items, allSchemas);
181
+ const itemType = (0, utils_1.swaggerTypeToTsType)(schema.items || {}, allSchemas);
182
182
  definition = `export type ${typeName} = ${itemType};`;
183
183
  }
184
184
  else if (schema.enum) {
185
185
  // 枚举类型
186
186
  const enumValues = schema.enum
187
187
  .map((value, index) => {
188
- let key = value;
189
- // 优先使用 x-enum-varnames 或 x-enumNames 扩展字段
190
- if ((schema['x-enum-varnames'] && schema['x-enum-varnames'][index]) ||
191
- (schema['x-enumNames'] && schema['x-enumNames'][index])) {
192
- key =
193
- schema['x-enum-varnames']?.[index] ||
194
- schema['x-enumNames']?.[index];
195
- }
196
- else if (/^\d+$/.test(value)) {
197
- // 对于数字枚举,使用 VALUE_ 前缀
198
- key = `VALUE_${value}`;
199
- }
200
- else {
201
- key = value.toUpperCase();
202
- }
188
+ const key = this.getEnumMemberName(schema, value, index);
203
189
  return ` ${key} = '${value}'`;
204
190
  })
205
191
  .join(',\n');
@@ -216,6 +202,24 @@ class SwaggerParser {
216
202
  description: schema.description
217
203
  };
218
204
  }
205
+ /**
206
+ * 获取枚举成员名称
207
+ * @param schema 枚举 schema
208
+ * @param value 枚举值
209
+ * @param index 枚举值索引
210
+ * @returns 枚举成员名称
211
+ */
212
+ getEnumMemberName(schema, value, index) {
213
+ const extensionName = schema['x-enum-varnames']?.[index] || schema['x-enumNames']?.[index];
214
+ if (extensionName) {
215
+ return extensionName;
216
+ }
217
+ const strValue = String(value);
218
+ if (/^\d+$/.test(strValue)) {
219
+ return `VALUE_${strValue}`;
220
+ }
221
+ return strValue.toUpperCase();
222
+ }
219
223
  /**
220
224
  * 解析本地 $ref 引用对象
221
225
  * @param value 可能带有 $ref 的对象
@@ -265,16 +269,7 @@ class SwaggerParser {
265
269
  }
266
270
  // 从路径操作中获取
267
271
  for (const pathItem of Object.values(this.document.paths)) {
268
- const methods = [
269
- 'get',
270
- 'post',
271
- 'put',
272
- 'delete',
273
- 'patch',
274
- 'head',
275
- 'options'
276
- ];
277
- for (const method of methods) {
272
+ for (const method of HTTP_METHODS) {
278
273
  const operation = pathItem[method];
279
274
  if (operation?.tags) {
280
275
  operation.tags.forEach((tag) => tags.add(tag));
@@ -286,6 +286,10 @@ export interface SwaggerSchema {
286
286
  externalDocs?: SwaggerExternalDocs;
287
287
  nullable?: boolean;
288
288
  deprecated?: boolean;
289
+ /** OpenAPI 扩展字段:枚举变量名 */
290
+ 'x-enum-varnames'?: string[];
291
+ /** OpenAPI 扩展字段:枚举名称 */
292
+ 'x-enumNames'?: string[];
289
293
  }
290
294
  /**
291
295
  * Swagger项目
@@ -1,8 +1,23 @@
1
- import { SwaggerParameter } from '../types';
1
+ import { ParameterInfo } from '../types';
2
+ /**
3
+ * 注释生成需要的操作信息
4
+ */
5
+ export interface ApiCommentOperation {
6
+ /** 接口摘要 */
7
+ summary?: string;
8
+ /** 接口描述 */
9
+ description?: string;
10
+ /** 是否废弃 */
11
+ deprecated?: boolean;
12
+ }
13
+ /**
14
+ * 注释生成需要的参数信息
15
+ */
16
+ export type ApiCommentParameter = Pick<ParameterInfo, 'in' | 'description'>;
2
17
  /**
3
18
  * 生成接口注释
4
- * @param operation Swagger操作对象
19
+ * @param operation 接口操作信息
5
20
  * @param parameters 参数列表
6
21
  * @returns 注释字符串
7
22
  */
8
- export declare function generateApiComment(operation: any, parameters: SwaggerParameter[]): string;
23
+ export declare function generateApiComment(operation: ApiCommentOperation, parameters: ApiCommentParameter[]): string;
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.generateApiComment = generateApiComment;
4
4
  /**
5
5
  * 生成接口注释
6
- * @param operation Swagger操作对象
6
+ * @param operation 接口操作信息
7
7
  * @param parameters 参数列表
8
8
  * @returns 注释字符串
9
9
  */
@@ -1,4 +1,4 @@
1
- import { SwaggerParameter } from '../types';
1
+ import { SwaggerParameter, SwaggerSchema, SwaggerResponses } from '../types';
2
2
  /**
3
3
  * 移除联合类型中的顶层 null 类型
4
4
  * @param typeStr 类型字符串
@@ -11,29 +11,31 @@ export declare function stripNullFromUnion(typeStr: string): string;
11
11
  * @param schemas 可选的 schemas 上下文,用于查找被引用的类型定义
12
12
  * @returns TypeScript类型字符串
13
13
  */
14
- export declare function swaggerTypeToTsType(schema: any, schemas?: any): string;
14
+ export declare function swaggerTypeToTsType(schema: SwaggerSchema | undefined | null, schemas?: Record<string, SwaggerSchema>): string;
15
+ /**
16
+ * 从 $ref 字符串中提取引用名称
17
+ * @param ref OpenAPI $ref 字符串
18
+ * @returns 引用名称
19
+ */
20
+ export declare function getRefName(ref: string): string;
15
21
  /**
16
22
  * 将 OpenAPI 参数转换为 schema 对象
17
23
  * @param parameter OpenAPI 参数
18
24
  * @returns 参数对应的 schema
19
25
  */
20
- export declare function swaggerParameterToSchema(parameter: SwaggerParameter): any;
21
- /**
22
- * 从 OpenAPI 参数生成 TypeScript 参数类型
23
- * @param parameters OpenAPI 参数数组
24
- * @returns TypeScript参数类型定义
25
- */
26
- export declare function generateParameterTypes(parameters: SwaggerParameter[]): string;
26
+ export declare function swaggerParameterToSchema(parameter: SwaggerParameter): SwaggerSchema;
27
27
  /**
28
28
  * 获取响应类型
29
29
  * @param responses OpenAPI 响应对象
30
30
  * @param schemas OpenAPI components.schemas
31
31
  * @returns TypeScript类型字符串
32
32
  */
33
- export declare function getResponseType(responses: any, schemas?: any): string;
33
+ export declare function getResponseType(responses: SwaggerResponses, schemas?: Record<string, SwaggerSchema>): string;
34
34
  /**
35
35
  * 从 OpenAPI content 对象中获取最合适的 schema
36
36
  * @param content OpenAPI content 对象
37
37
  * @returns 匹配到的 schema
38
38
  */
39
- export declare function getSchemaFromContent(content: any): any;
39
+ export declare function getSchemaFromContent(content: Record<string, {
40
+ schema?: SwaggerSchema;
41
+ }> | undefined): SwaggerSchema | undefined;
@@ -2,8 +2,8 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.stripNullFromUnion = stripNullFromUnion;
4
4
  exports.swaggerTypeToTsType = swaggerTypeToTsType;
5
+ exports.getRefName = getRefName;
5
6
  exports.swaggerParameterToSchema = swaggerParameterToSchema;
6
- exports.generateParameterTypes = generateParameterTypes;
7
7
  exports.getResponseType = getResponseType;
8
8
  exports.getSchemaFromContent = getSchemaFromContent;
9
9
  const naming_1 = require("./naming");
@@ -79,7 +79,7 @@ function swaggerTypeToTsType(schema, schemas) {
79
79
  const refSchema = schema.allOf.find((item) => item.$ref);
80
80
  const secondSchema = schema.allOf.find((item) => !item.$ref);
81
81
  if (refSchema && secondSchema) {
82
- const refName = refSchema.$ref.split('/').pop();
82
+ const refName = getRefName(refSchema.$ref || '');
83
83
  const sanitizedRefName = (0, naming_1.sanitizeTypeName)(refName || '');
84
84
  if (secondSchema.properties) {
85
85
  const propertyTypes = [];
@@ -132,7 +132,7 @@ function swaggerTypeToTsType(schema, schemas) {
132
132
  }
133
133
  }
134
134
  else if (schema.$ref) {
135
- const refName = schema.$ref.split('/').pop();
135
+ const refName = getRefName(schema.$ref);
136
136
  baseType = (0, naming_1.sanitizeTypeName)(refName || 'any');
137
137
  if (schemas && refName) {
138
138
  const referencedSchema = schemas[refName];
@@ -145,7 +145,7 @@ function swaggerTypeToTsType(schema, schemas) {
145
145
  const itemSchema = schema.items;
146
146
  const itemType = swaggerTypeToTsType(itemSchema, schemas);
147
147
  if (itemSchema?.$ref && schemas) {
148
- const refName = itemSchema.$ref.split('/').pop();
148
+ const refName = getRefName(itemSchema.$ref);
149
149
  const referencedSchema = refName ? schemas[refName] : undefined;
150
150
  baseType =
151
151
  referencedSchema?.type === 'array' ? itemType : `${itemType}[]`;
@@ -211,6 +211,14 @@ function swaggerTypeToTsType(schema, schemas) {
211
211
  }
212
212
  return baseType;
213
213
  }
214
+ /**
215
+ * 从 $ref 字符串中提取引用名称
216
+ * @param ref OpenAPI $ref 字符串
217
+ * @returns 引用名称
218
+ */
219
+ function getRefName(ref) {
220
+ return ref.split('/').pop() || '';
221
+ }
214
222
  /**
215
223
  * 将枚举值转换为 TypeScript 字面量类型
216
224
  * @param value 枚举值
@@ -239,41 +247,6 @@ function swaggerParameterToSchema(parameter) {
239
247
  enum: parameter.enum
240
248
  };
241
249
  }
242
- /**
243
- * 从 OpenAPI 参数生成 TypeScript 参数类型
244
- * @param parameters OpenAPI 参数数组
245
- * @returns TypeScript参数类型定义
246
- */
247
- function generateParameterTypes(parameters) {
248
- if (!parameters || parameters.length === 0) {
249
- return '';
250
- }
251
- const queryParams = parameters.filter((param) => param.in === 'query');
252
- const pathParams = parameters.filter((param) => param.in === 'path');
253
- const bodyParams = parameters.filter((param) => param.in === 'body');
254
- const types = [];
255
- if (pathParams.length > 0) {
256
- const pathType = pathParams
257
- .map((param) => `${param.name}: ${swaggerTypeToTsType(swaggerParameterToSchema(param))}`)
258
- .join(', ');
259
- types.push(`pathParams: { ${pathType} }`);
260
- }
261
- if (queryParams.length > 0) {
262
- const queryType = queryParams
263
- .map((param) => {
264
- const optional = param.required ? '' : '?';
265
- return `${param.name}${optional}: ${swaggerTypeToTsType(swaggerParameterToSchema(param))}`;
266
- })
267
- .join(', ');
268
- types.push(`queryParams${queryParams.every((param) => !param.required) ? '?' : ''}: { ${queryType} }`);
269
- }
270
- if (bodyParams.length > 0) {
271
- const bodyParam = bodyParams[0];
272
- const bodyType = swaggerTypeToTsType(bodyParam.schema);
273
- types.push(`data: ${bodyType}`);
274
- }
275
- return types.join(', ');
276
- }
277
250
  /**
278
251
  * 获取响应类型
279
252
  * @param responses OpenAPI 响应对象
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "swagger2api-v3",
3
- "version": "1.1.8",
4
- "description": "A command-line tool for generating TypeScript API interfaces from Swagger (OAS 3.0) documentation",
3
+ "version": "1.1.9",
4
+ "description": "A command-line tool for generating TypeScript API interfaces from OpenAPI 3.x / Swagger 3.0 documentation",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
7
  "type": "commonjs",
@@ -54,12 +54,12 @@
54
54
  },
55
55
  "packageManager": "pnpm@10.11.0",
56
56
  "devDependencies": {
57
- "@types/jest": "^29.5.0",
57
+ "@types/jest": "^30.0.0",
58
58
  "@types/node": "^24.3.1",
59
- "jest": "^29.5.0",
59
+ "jest": "^30.4.2",
60
60
  "prettier": "^3.6.2",
61
61
  "rimraf": "^6.0.1",
62
- "ts-jest": "^29.1.0",
62
+ "ts-jest": "^29.4.11",
63
63
  "typescript": "^5.9.2"
64
64
  },
65
65
  "dependencies": {