swagger2api-v3 1.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.
@@ -0,0 +1,318 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.pathToFunctionName = pathToFunctionName;
40
+ exports.toKebabCase = toKebabCase;
41
+ exports.toPascalCase = toPascalCase;
42
+ exports.toCamelCase = toCamelCase;
43
+ exports.swaggerTypeToTsType = swaggerTypeToTsType;
44
+ exports.generateParameterTypes = generateParameterTypes;
45
+ exports.ensureDirectoryExists = ensureDirectoryExists;
46
+ exports.removeDirectory = removeDirectory;
47
+ exports.loadSwaggerDocument = loadSwaggerDocument;
48
+ exports.writeFile = writeFile;
49
+ exports.generateApiComment = generateApiComment;
50
+ exports.sanitizeFilename = sanitizeFilename;
51
+ exports.getResponseType = getResponseType;
52
+ const fs = __importStar(require("fs"));
53
+ const path = __importStar(require("path"));
54
+ const axios_1 = __importDefault(require("axios"));
55
+ /**
56
+ * 工具函数集合
57
+ */
58
+ /**
59
+ * 将路径转换为小驼峰命名的函数名
60
+ * @param method HTTP方法
61
+ * @param path 接口路径
62
+ * @returns 小驼峰命名的函数名
63
+ */
64
+ function pathToFunctionName(method, path) {
65
+ // 移除路径参数的大括号
66
+ const cleanPath = path.replace(/\{([^}]+)\}/g, '$1');
67
+ // 分割路径并过滤空字符串
68
+ const segments = cleanPath.split('/').filter(segment => segment.length > 0);
69
+ // 将方法名添加到开头
70
+ const parts = [method.toLowerCase(), ...segments];
71
+ // 转换为小驼峰命名
72
+ return parts
73
+ .map((part, index) => {
74
+ // 移除特殊字符并转换为小驼峰
75
+ const cleanPart = part.replace(/[^a-zA-Z0-9]/g, '');
76
+ if (index === 0) {
77
+ return cleanPart.toLowerCase();
78
+ }
79
+ return cleanPart.charAt(0).toUpperCase() + cleanPart.slice(1).toLowerCase();
80
+ })
81
+ .join('');
82
+ }
83
+ /**
84
+ * 将字符串转换为kebab-case
85
+ * @param str 输入字符串
86
+ * @returns kebab-case字符串
87
+ */
88
+ function toKebabCase(str) {
89
+ return str
90
+ .replace(/([a-z])([A-Z])/g, '$1-$2')
91
+ .replace(/[\s_]+/g, '-')
92
+ .toLowerCase();
93
+ }
94
+ /**
95
+ * 将字符串转换为PascalCase
96
+ * @param str 输入字符串
97
+ * @returns PascalCase字符串
98
+ */
99
+ function toPascalCase(str) {
100
+ return str
101
+ .replace(/[\s-_]+(.)?/g, (_, char) => char ? char.toUpperCase() : '')
102
+ .replace(/^(.)/, char => char.toUpperCase());
103
+ }
104
+ /**
105
+ * 将字符串转换为camelCase
106
+ * @param str 输入字符串
107
+ * @returns camelCase字符串
108
+ */
109
+ function toCamelCase(str) {
110
+ const pascalCase = toPascalCase(str);
111
+ return pascalCase.charAt(0).toLowerCase() + pascalCase.slice(1);
112
+ }
113
+ /**
114
+ * 将Swagger类型转换为TypeScript类型
115
+ * @param schema Swagger模式
116
+ * @returns TypeScript类型字符串
117
+ */
118
+ function swaggerTypeToTsType(schema) {
119
+ if (!schema) {
120
+ return 'any';
121
+ }
122
+ // 处理引用类型
123
+ if (schema.$ref) {
124
+ const refName = schema.$ref.split('/').pop();
125
+ return refName || 'any';
126
+ }
127
+ // 处理数组类型
128
+ if (schema.type === 'array') {
129
+ const itemType = swaggerTypeToTsType(schema.items);
130
+ return `${itemType}[]`;
131
+ }
132
+ // 处理对象类型
133
+ if (schema.type === 'object') {
134
+ if (schema.properties) {
135
+ const properties = Object.entries(schema.properties)
136
+ .map(([key, value]) => {
137
+ const optional = schema.required?.includes(key) ? '' : '?';
138
+ const type = swaggerTypeToTsType(value);
139
+ return ` ${key}${optional}: ${type};`;
140
+ })
141
+ .join('\n');
142
+ return `{\n${properties}\n}`;
143
+ }
144
+ return 'Record<string, any>';
145
+ }
146
+ // 处理基本类型
147
+ switch (schema.type) {
148
+ case 'integer':
149
+ case 'number':
150
+ return 'number';
151
+ case 'string':
152
+ if (schema.enum) {
153
+ return schema.enum.map(value => `'${value}'`).join(' | ');
154
+ }
155
+ return 'string';
156
+ case 'boolean':
157
+ return 'boolean';
158
+ case 'file':
159
+ return 'File';
160
+ default:
161
+ return 'any';
162
+ }
163
+ }
164
+ /**
165
+ * 从Swagger参数生成TypeScript参数类型
166
+ * @param parameters Swagger参数数组
167
+ * @returns TypeScript参数类型定义
168
+ */
169
+ function generateParameterTypes(parameters) {
170
+ if (!parameters || parameters.length === 0) {
171
+ return '';
172
+ }
173
+ const queryParams = parameters.filter(p => p.in === 'query');
174
+ const pathParams = parameters.filter(p => p.in === 'path');
175
+ const bodyParams = parameters.filter(p => p.in === 'body');
176
+ const formParams = parameters.filter(p => p.in === 'formData');
177
+ const types = [];
178
+ // 路径参数
179
+ if (pathParams.length > 0) {
180
+ const pathType = pathParams
181
+ .map(p => `${p.name}: ${swaggerTypeToTsType({ type: p.type || 'string' })}`)
182
+ .join(', ');
183
+ types.push(`pathParams: { ${pathType} }`);
184
+ }
185
+ // 查询参数
186
+ if (queryParams.length > 0) {
187
+ const queryType = queryParams
188
+ .map(p => {
189
+ const optional = p.required ? '' : '?';
190
+ return `${p.name}${optional}: ${swaggerTypeToTsType({ type: p.type || 'string' })}`;
191
+ })
192
+ .join(', ');
193
+ types.push(`queryParams${queryParams.every(p => !p.required) ? '?' : ''}: { ${queryType} }`);
194
+ }
195
+ // 请求体参数
196
+ if (bodyParams.length > 0) {
197
+ const bodyParam = bodyParams[0];
198
+ const bodyType = swaggerTypeToTsType(bodyParam.schema);
199
+ types.push(`data: ${bodyType}`);
200
+ }
201
+ // 表单参数
202
+ if (formParams.length > 0) {
203
+ const formType = formParams
204
+ .map(p => {
205
+ const optional = p.required ? '' : '?';
206
+ return `${p.name}${optional}: ${swaggerTypeToTsType({ type: p.type || 'string' })}`;
207
+ })
208
+ .join(', ');
209
+ types.push(`data: { ${formType} }`);
210
+ }
211
+ return types.join(', ');
212
+ }
213
+ /**
214
+ * 确保目录存在,如果不存在则创建
215
+ * @param dirPath 目录路径
216
+ */
217
+ function ensureDirectoryExists(dirPath) {
218
+ if (!fs.existsSync(dirPath)) {
219
+ fs.mkdirSync(dirPath, { recursive: true });
220
+ }
221
+ }
222
+ /**
223
+ * 删除目录及其所有内容
224
+ * @param dirPath 目录路径
225
+ */
226
+ function removeDirectory(dirPath) {
227
+ if (fs.existsSync(dirPath)) {
228
+ fs.rmSync(dirPath, { recursive: true, force: true });
229
+ }
230
+ }
231
+ /**
232
+ * 读取Swagger文档
233
+ * @param input 文件路径或URL
234
+ * @returns Swagger文档对象
235
+ */
236
+ async function loadSwaggerDocument(input) {
237
+ try {
238
+ if (input.startsWith('http://') || input.startsWith('https://')) {
239
+ // 从URL加载
240
+ const response = await axios_1.default.get(input);
241
+ return response.data;
242
+ }
243
+ else {
244
+ // 从文件加载
245
+ const content = fs.readFileSync(input, 'utf-8');
246
+ return JSON.parse(content);
247
+ }
248
+ }
249
+ catch (error) {
250
+ throw new Error(`Failed to load Swagger document from ${input}: ${error}`);
251
+ }
252
+ }
253
+ /**
254
+ * 写入文件
255
+ * @param filePath 文件路径
256
+ * @param content 文件内容
257
+ */
258
+ function writeFile(filePath, content) {
259
+ const dir = path.dirname(filePath);
260
+ ensureDirectoryExists(dir);
261
+ fs.writeFileSync(filePath, content, 'utf-8');
262
+ }
263
+ /**
264
+ * 生成接口注释
265
+ * @param operation Swagger操作对象
266
+ * @param parameters 参数列表
267
+ * @returns 注释字符串
268
+ */
269
+ function generateApiComment(operation, parameters) {
270
+ const comments = ['/**'];
271
+ if (operation.summary) {
272
+ comments.push(` * ${operation.summary}`);
273
+ }
274
+ if (operation.description && operation.description !== operation.summary) {
275
+ comments.push(` * ${operation.description}`);
276
+ }
277
+ if (parameters && parameters.length > 0) {
278
+ comments.push(' *');
279
+ parameters.forEach(param => {
280
+ const description = param.description || '';
281
+ comments.push(` * @param ${param.name} ${description}`);
282
+ });
283
+ }
284
+ if (operation.deprecated) {
285
+ comments.push(' * @deprecated');
286
+ }
287
+ comments.push(' */');
288
+ return comments.join('\n');
289
+ }
290
+ /**
291
+ * 清理文件名,移除非法字符
292
+ * @param filename 文件名
293
+ * @returns 清理后的文件名
294
+ */
295
+ function sanitizeFilename(filename) {
296
+ return filename.replace(/[<>:"/\\|?*]/g, '-').replace(/\s+/g, '-');
297
+ }
298
+ /**
299
+ * 获取响应类型
300
+ * @param responses Swagger响应对象
301
+ * @returns TypeScript类型字符串
302
+ */
303
+ function getResponseType(responses) {
304
+ // 优先获取200响应
305
+ const successResponse = responses['200'] || responses['201'] || responses['default'];
306
+ if (!successResponse) {
307
+ return 'any';
308
+ }
309
+ // 支持OpenAPI 3.0格式 (content.application/json.schema)
310
+ if (successResponse.content && successResponse.content['application/json'] && successResponse.content['application/json'].schema) {
311
+ return swaggerTypeToTsType(successResponse.content['application/json'].schema);
312
+ }
313
+ // 支持Swagger 2.0格式 (直接schema)
314
+ if (successResponse.schema) {
315
+ return swaggerTypeToTsType(successResponse.schema);
316
+ }
317
+ return 'any';
318
+ }
@@ -0,0 +1,17 @@
1
+ import { type AxiosRequestConfig, type AxiosResponse, type CreateAxiosDefaults, type InternalAxiosRequestConfig } from 'axios';
2
+ export interface IReqBoay<T> {
3
+ code: number;
4
+ data: T;
5
+ message: string;
6
+ }
7
+ declare class HttpRequest {
8
+ private instance;
9
+ constructor(options: CreateAxiosDefaults);
10
+ requestInterceptors(config: InternalAxiosRequestConfig): InternalAxiosRequestConfig<any>;
11
+ responseInterceptors(response: AxiosResponse): any;
12
+ private request;
13
+ get<T = any>({ ...config }: AxiosRequestConfig): Promise<IReqBoay<T>>;
14
+ post<T = any>({ ...config }: AxiosRequestConfig): Promise<IReqBoay<T>>;
15
+ }
16
+ export declare const request: HttpRequest;
17
+ export {};
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.request = void 0;
7
+ const axios_1 = __importDefault(require("axios"));
8
+ class HttpRequest {
9
+ constructor(options) {
10
+ this.instance = axios_1.default.create(options);
11
+ this.instance.interceptors.request.use(this.requestInterceptors);
12
+ this.instance.interceptors.response.use(this.responseInterceptors);
13
+ }
14
+ requestInterceptors(config) {
15
+ return config;
16
+ }
17
+ responseInterceptors(response) {
18
+ return response.data;
19
+ }
20
+ request(config) {
21
+ return new Promise((resolve, reject) => {
22
+ this.instance
23
+ .request(config)
24
+ .then((res) => {
25
+ console.log('request:', res);
26
+ resolve(res);
27
+ })
28
+ .catch((err) => {
29
+ reject(err.message);
30
+ });
31
+ });
32
+ }
33
+ get({ ...config }) {
34
+ return this.request({
35
+ ...config,
36
+ method: 'GET'
37
+ });
38
+ }
39
+ post({ ...config }) {
40
+ return this.request({
41
+ ...config,
42
+ method: 'POST'
43
+ });
44
+ }
45
+ }
46
+ exports.request = new HttpRequest({
47
+ baseURL: ``,
48
+ timeout: 20000
49
+ });
package/package.json ADDED
@@ -0,0 +1,68 @@
1
+ {
2
+ "name": "swagger2api-v3",
3
+ "version": "1.0.0",
4
+ "description": "从 Swagger/OpenAPI 文档生成 TypeScript API 接口的命令行工具",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "bin": {
8
+ "swagger2api-v3": "dist/cli/index.js"
9
+ },
10
+ "files": [
11
+ "dist",
12
+ "README.md",
13
+ "package.json"
14
+ ],
15
+ "scripts": {
16
+ "test": "jest",
17
+ "test:watch": "jest --watch",
18
+ "test:coverage": "jest --coverage",
19
+ "test:ci": "jest --ci --coverage --watchAll=false",
20
+ "build": "tsc",
21
+ "clean": "rimraf dist",
22
+ "prebuild": "npm run clean",
23
+ "start": "node dist/cli/index.js",
24
+ "dev": "npm run build && npm start",
25
+ "lint": "prettier --write",
26
+ "generate": "npm run build && node dist/cli/index.js generate",
27
+ "init": "npm run build && node dist/cli/index.js init",
28
+ "validate": "npm run build && node dist/cli/index.js validate",
29
+ "swagger:generate": "npm run generate",
30
+ "swagger:run": "npm run generate",
31
+ "swagger:init": "npm run init",
32
+ "swagger:validate": "npm run validate"
33
+ },
34
+ "keywords": [
35
+ "swagger",
36
+ "openapi",
37
+ "typescript",
38
+ "api",
39
+ "generator",
40
+ "cli",
41
+ "code-generation"
42
+ ],
43
+ "author": "xiaoyang",
44
+ "license": "MIT",
45
+ "homepage": "https://github.com/xiaoyang33/swagger2api#readme",
46
+ "repository": {
47
+ "type": "git",
48
+ "url": "https://github.com/xiaoyang33/swagger2api.git"
49
+ },
50
+ "bugs": {
51
+ "url": "https://github.com/xiaoyang33/swagger2api/issues"
52
+ },
53
+ "packageManager": "pnpm@10.11.0",
54
+ "type": "commonjs",
55
+ "devDependencies": {
56
+ "@types/jest": "^29.5.0",
57
+ "@types/node": "^24.3.1",
58
+ "jest": "^29.5.0",
59
+ "prettier": "^3.6.2",
60
+ "rimraf": "^6.0.1",
61
+ "ts-jest": "^29.1.0",
62
+ "typescript": "^5.9.2"
63
+ },
64
+ "dependencies": {
65
+ "axios": "^1.11.0",
66
+ "commander": "^12.0.0"
67
+ }
68
+ }