swagger2api-v3 1.1.6 → 1.1.8
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 +15 -1
- package/dist/.swagger2api.schema.json +120 -0
- package/dist/cli/index.js +119 -47
- package/dist/config/validator.d.ts +7 -0
- package/dist/config/validator.js +218 -0
- package/dist/core/generator.d.ts +7 -1
- package/dist/core/generator.js +26 -44
- package/dist/core/parser.d.ts +13 -1
- package/dist/core/parser.js +54 -40
- package/dist/index.d.ts +6 -0
- package/dist/index.js +21 -13
- package/dist/types/index.d.ts +75 -38
- package/dist/utils/comment.d.ts +8 -0
- package/dist/utils/comment.js +47 -0
- package/dist/utils/file.d.ts +23 -0
- package/dist/utils/file.js +98 -0
- package/dist/utils/index.d.ts +4 -99
- package/dist/utils/index.js +6 -572
- package/dist/utils/naming.d.ts +51 -0
- package/dist/utils/naming.js +124 -0
- package/dist/utils/type.d.ts +39 -0
- package/dist/utils/type.js +331 -0
- package/package.json +3 -2
package/dist/utils/index.js
CHANGED
|
@@ -10,577 +10,11 @@ var __createBinding = (this && this.__createBinding) || (Object.create ? (functi
|
|
|
10
10
|
if (k2 === undefined) k2 = k;
|
|
11
11
|
o[k2] = m[k];
|
|
12
12
|
}));
|
|
13
|
-
var
|
|
14
|
-
|
|
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 };
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
37
15
|
};
|
|
38
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
-
exports
|
|
40
|
-
exports
|
|
41
|
-
exports
|
|
42
|
-
exports
|
|
43
|
-
exports.stripMethodNamePrefixes = stripMethodNamePrefixes;
|
|
44
|
-
exports.removeMethodSuffix = removeMethodSuffix;
|
|
45
|
-
exports.stripNullFromUnion = stripNullFromUnion;
|
|
46
|
-
exports.swaggerTypeToTsType = swaggerTypeToTsType;
|
|
47
|
-
exports.generateParameterTypes = generateParameterTypes;
|
|
48
|
-
exports.ensureDirectoryExists = ensureDirectoryExists;
|
|
49
|
-
exports.removeDirectory = removeDirectory;
|
|
50
|
-
exports.loadSwaggerDocument = loadSwaggerDocument;
|
|
51
|
-
exports.writeFile = writeFile;
|
|
52
|
-
exports.generateApiComment = generateApiComment;
|
|
53
|
-
exports.sanitizeFilename = sanitizeFilename;
|
|
54
|
-
exports.getResponseType = getResponseType;
|
|
55
|
-
exports.sanitizeTypeName = sanitizeTypeName;
|
|
56
|
-
const fs = __importStar(require("fs"));
|
|
57
|
-
const path = __importStar(require("path"));
|
|
58
|
-
const axios_1 = __importDefault(require("axios"));
|
|
59
|
-
/**
|
|
60
|
-
* 工具函数集合
|
|
61
|
-
*/
|
|
62
|
-
/**
|
|
63
|
-
* 将路径转换为小驼峰命名的函数名
|
|
64
|
-
* @param method HTTP方法
|
|
65
|
-
* @param path 接口路径
|
|
66
|
-
* @returns 小驼峰命名的函数名
|
|
67
|
-
*/
|
|
68
|
-
function pathToFunctionName(method, path) {
|
|
69
|
-
// 移除路径参数的大括号
|
|
70
|
-
const cleanPath = path.replace(/\{([^}]+)\}/g, '$1');
|
|
71
|
-
// 分割路径并过滤空字符串
|
|
72
|
-
const segments = cleanPath.split('/').filter((segment) => segment.length > 0);
|
|
73
|
-
// 将路径段转换为驼峰命名
|
|
74
|
-
const pathParts = segments.map((part, index) => {
|
|
75
|
-
// 移除特殊字符并转换为小驼峰
|
|
76
|
-
const cleanPart = part.replace(/[^a-zA-Z0-9]/g, '');
|
|
77
|
-
if (index === 0) {
|
|
78
|
-
return cleanPart.toLowerCase();
|
|
79
|
-
}
|
|
80
|
-
return cleanPart.charAt(0).toUpperCase() + cleanPart.slice(1).toLowerCase();
|
|
81
|
-
});
|
|
82
|
-
// 将HTTP方法转换为首字母大写的形式并添加到末尾
|
|
83
|
-
const methodSuffix = method.charAt(0).toUpperCase() + method.slice(1).toLowerCase();
|
|
84
|
-
// 组合路径名称和方法名称
|
|
85
|
-
const baseName = pathParts.join('');
|
|
86
|
-
return baseName + methodSuffix;
|
|
87
|
-
}
|
|
88
|
-
/**
|
|
89
|
-
* 将字符串转换为kebab-case
|
|
90
|
-
* @param str 输入字符串
|
|
91
|
-
* @returns kebab-case字符串
|
|
92
|
-
*/
|
|
93
|
-
function toKebabCase(str) {
|
|
94
|
-
return str
|
|
95
|
-
.replace(/([a-z])([A-Z])/g, '$1-$2')
|
|
96
|
-
.replace(/[\s_]+/g, '-')
|
|
97
|
-
.toLowerCase();
|
|
98
|
-
}
|
|
99
|
-
/**
|
|
100
|
-
* 将字符串转换为PascalCase
|
|
101
|
-
* @param str 输入字符串
|
|
102
|
-
* @returns PascalCase字符串
|
|
103
|
-
*/
|
|
104
|
-
function toPascalCase(str) {
|
|
105
|
-
return str
|
|
106
|
-
.replace(/[\s-_]+(.)?/g, (_, char) => (char ? char.toUpperCase() : ''))
|
|
107
|
-
.replace(/^(.)/, (char) => char.toUpperCase());
|
|
108
|
-
}
|
|
109
|
-
/**
|
|
110
|
-
* 将字符串转换为camelCase
|
|
111
|
-
* @param str 输入字符串
|
|
112
|
-
* @returns camelCase字符串
|
|
113
|
-
*/
|
|
114
|
-
function toCamelCase(str) {
|
|
115
|
-
const pascalCase = toPascalCase(str);
|
|
116
|
-
return pascalCase.charAt(0).toLowerCase() + pascalCase.slice(1);
|
|
117
|
-
}
|
|
118
|
-
/**
|
|
119
|
-
* 从方法名中移除指定的前缀
|
|
120
|
-
* @param methodName 方法名
|
|
121
|
-
* @param prefixes 需要移除的前缀数组
|
|
122
|
-
* @returns 移除前缀后的方法名
|
|
123
|
-
*/
|
|
124
|
-
function stripMethodNamePrefixes(methodName, prefixes) {
|
|
125
|
-
if (!prefixes || prefixes.length === 0) {
|
|
126
|
-
return methodName;
|
|
127
|
-
}
|
|
128
|
-
let result = methodName;
|
|
129
|
-
// 循环移除所有匹配的前缀,直到没有前缀可以移除
|
|
130
|
-
let changed = true;
|
|
131
|
-
while (changed) {
|
|
132
|
-
changed = false;
|
|
133
|
-
for (const prefix of prefixes) {
|
|
134
|
-
if (!prefix)
|
|
135
|
-
continue;
|
|
136
|
-
// 将前缀转换为小驼峰格式进行匹配
|
|
137
|
-
const camelPrefix = toCamelCase(prefix);
|
|
138
|
-
// 检查方法名是否以该前缀开头(不区分大小写)
|
|
139
|
-
const lowerMethodName = result.toLowerCase();
|
|
140
|
-
const lowerPrefix = camelPrefix.toLowerCase();
|
|
141
|
-
if (lowerMethodName.startsWith(lowerPrefix)) {
|
|
142
|
-
// 移除前缀,保持后续字符的大小写
|
|
143
|
-
const remaining = result.substring(camelPrefix.length);
|
|
144
|
-
// 如果移除前缀后还有内容,则更新结果
|
|
145
|
-
if (remaining.length > 0) {
|
|
146
|
-
// 确保首字母小写
|
|
147
|
-
result = remaining.charAt(0).toLowerCase() + remaining.slice(1);
|
|
148
|
-
changed = true;
|
|
149
|
-
break; // 重新开始检查
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
return result;
|
|
155
|
-
}
|
|
156
|
-
/**
|
|
157
|
-
* 从函数名中移除 HTTP method 后缀
|
|
158
|
-
* @param functionName 函数名
|
|
159
|
-
* @param method HTTP 方法
|
|
160
|
-
* @returns 移除后缀后的函数名
|
|
161
|
-
*/
|
|
162
|
-
function removeMethodSuffix(functionName, method) {
|
|
163
|
-
const methodSuffix = method.charAt(0).toUpperCase() + method.slice(1).toLowerCase();
|
|
164
|
-
if (functionName.endsWith(methodSuffix)) {
|
|
165
|
-
return functionName.slice(0, -methodSuffix.length);
|
|
166
|
-
}
|
|
167
|
-
return functionName;
|
|
168
|
-
}
|
|
169
|
-
function stripNullFromUnion(typeStr) {
|
|
170
|
-
if (!typeStr)
|
|
171
|
-
return 'any';
|
|
172
|
-
const parts = [];
|
|
173
|
-
let current = '';
|
|
174
|
-
let parenDepth = 0;
|
|
175
|
-
let angleDepth = 0;
|
|
176
|
-
let braceDepth = 0;
|
|
177
|
-
let bracketDepth = 0;
|
|
178
|
-
for (let i = 0; i < typeStr.length; i++) {
|
|
179
|
-
const ch = typeStr[i];
|
|
180
|
-
if (ch === '(')
|
|
181
|
-
parenDepth++;
|
|
182
|
-
else if (ch === ')')
|
|
183
|
-
parenDepth = Math.max(0, parenDepth - 1);
|
|
184
|
-
else if (ch === '<')
|
|
185
|
-
angleDepth++;
|
|
186
|
-
else if (ch === '>')
|
|
187
|
-
angleDepth = Math.max(0, angleDepth - 1);
|
|
188
|
-
else if (ch === '{')
|
|
189
|
-
braceDepth++;
|
|
190
|
-
else if (ch === '}')
|
|
191
|
-
braceDepth = Math.max(0, braceDepth - 1);
|
|
192
|
-
else if (ch === '[')
|
|
193
|
-
bracketDepth++;
|
|
194
|
-
else if (ch === ']')
|
|
195
|
-
bracketDepth = Math.max(0, bracketDepth - 1);
|
|
196
|
-
const isTopLevel = parenDepth === 0 &&
|
|
197
|
-
angleDepth === 0 &&
|
|
198
|
-
braceDepth === 0 &&
|
|
199
|
-
bracketDepth === 0;
|
|
200
|
-
if (ch === '|' && isTopLevel) {
|
|
201
|
-
parts.push(current.trim());
|
|
202
|
-
current = '';
|
|
203
|
-
continue;
|
|
204
|
-
}
|
|
205
|
-
current += ch;
|
|
206
|
-
}
|
|
207
|
-
if (current.trim())
|
|
208
|
-
parts.push(current.trim());
|
|
209
|
-
const normalized = Array.from(new Set(parts.filter((p) => p && p !== 'null')));
|
|
210
|
-
return normalized.length > 0 ? normalized.join(' | ') : 'any';
|
|
211
|
-
}
|
|
212
|
-
/**
|
|
213
|
-
* 将Swagger类型转换为TypeScript类型
|
|
214
|
-
* @param schema Swagger模式
|
|
215
|
-
* @param schemas 可选的 schemas 上下文,用于查找被引用的类型定义
|
|
216
|
-
* @returns TypeScript类型字符串
|
|
217
|
-
*/
|
|
218
|
-
function swaggerTypeToTsType(schema, schemas) {
|
|
219
|
-
if (!schema)
|
|
220
|
-
return 'any';
|
|
221
|
-
let baseType = 'any';
|
|
222
|
-
// 处理 allOf (通常用于继承或泛型)
|
|
223
|
-
if (schema.allOf) {
|
|
224
|
-
// 简单处理:如果是引用 + 对象定义,可能是泛型包装
|
|
225
|
-
const refSchema = schema.allOf.find((s) => s.$ref);
|
|
226
|
-
const secondSchema = schema.allOf.find((s) => !s.$ref);
|
|
227
|
-
if (refSchema && secondSchema) {
|
|
228
|
-
const refName = refSchema.$ref.split('/').pop();
|
|
229
|
-
const sanitizedRefName = sanitizeTypeName(refName || '');
|
|
230
|
-
// 检查是否是泛型容器 (如 ResOp)
|
|
231
|
-
// 注意:secondSchema 可能没有显式声明 type: 'object',但如果有 properties,则视为对象
|
|
232
|
-
if (secondSchema.properties) {
|
|
233
|
-
// 尝试提取泛型参数类型
|
|
234
|
-
// 这里假设泛型参数是 properties 中的第一个属性
|
|
235
|
-
const propertyTypes = [];
|
|
236
|
-
for (const [propName, propSchema] of Object.entries(secondSchema.properties)) {
|
|
237
|
-
const propType = swaggerTypeToTsType(propSchema, schemas);
|
|
238
|
-
propertyTypes.push(propType);
|
|
239
|
-
}
|
|
240
|
-
// 如果只有一个属性,直接作为泛型参数
|
|
241
|
-
if (propertyTypes.length === 1) {
|
|
242
|
-
baseType = `${sanitizedRefName}<${propertyTypes[0]}>`;
|
|
243
|
-
}
|
|
244
|
-
// 如果有多个属性,组合成联合类型或对象类型
|
|
245
|
-
else if (propertyTypes.length > 1) {
|
|
246
|
-
const combinedType = `{ ${Object.entries(secondSchema.properties)
|
|
247
|
-
.map(([key, value]) => {
|
|
248
|
-
const optional = secondSchema.required?.includes(key) ? '' : '?';
|
|
249
|
-
let type = swaggerTypeToTsType(value, schemas);
|
|
250
|
-
if (optional === '?')
|
|
251
|
-
type = stripNullFromUnion(type);
|
|
252
|
-
return `${key}${optional}: ${type}`;
|
|
253
|
-
})
|
|
254
|
-
.join('; ')} }`;
|
|
255
|
-
baseType = `${sanitizedRefName}<${combinedType}>`;
|
|
256
|
-
}
|
|
257
|
-
else {
|
|
258
|
-
baseType = sanitizedRefName || 'any';
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
else {
|
|
262
|
-
baseType = sanitizedRefName || 'any';
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
else {
|
|
266
|
-
// 如果不是引用,尝试合并所有类型
|
|
267
|
-
const types = schema.allOf
|
|
268
|
-
.map((s) => swaggerTypeToTsType(s))
|
|
269
|
-
.filter((t) => t !== 'any');
|
|
270
|
-
baseType = types.length > 0 ? types[0] : 'any';
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
// 处理 anyOf 或 oneOf
|
|
274
|
-
else if (schema.anyOf || schema.oneOf) {
|
|
275
|
-
const types = (schema.anyOf || schema.oneOf).map((s) => {
|
|
276
|
-
// 特殊处理 type: 'null'
|
|
277
|
-
if (s.type === 'null')
|
|
278
|
-
return 'null';
|
|
279
|
-
return swaggerTypeToTsType(s, schemas);
|
|
280
|
-
});
|
|
281
|
-
// 如果包含 any,则直接返回 any
|
|
282
|
-
if (types.includes('any')) {
|
|
283
|
-
baseType = 'any';
|
|
284
|
-
}
|
|
285
|
-
else {
|
|
286
|
-
// 去重
|
|
287
|
-
const uniqueTypes = Array.from(new Set(types));
|
|
288
|
-
if (uniqueTypes.length > 0) {
|
|
289
|
-
baseType = uniqueTypes.join(' | ');
|
|
290
|
-
}
|
|
291
|
-
else {
|
|
292
|
-
baseType = 'any';
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
// 处理引用类型
|
|
297
|
-
else if (schema.$ref) {
|
|
298
|
-
const refName = schema.$ref.split('/').pop();
|
|
299
|
-
baseType = sanitizeTypeName(refName || 'any');
|
|
300
|
-
// 如果提供了 schemas 上下文,检查被引用的 schema 是否是数组类型
|
|
301
|
-
if (schemas &&
|
|
302
|
-
refName &&
|
|
303
|
-
typeof schema.$ref === 'string' &&
|
|
304
|
-
schema.$ref.startsWith('#/')) {
|
|
305
|
-
const referencedSchema = schemas[refName];
|
|
306
|
-
if (referencedSchema && referencedSchema.type === 'array') {
|
|
307
|
-
// 被引用的 schema 是数组类型,添加 []
|
|
308
|
-
baseType = `${baseType}[]`;
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
// 处理数组类型
|
|
313
|
-
else if (schema.type === 'array') {
|
|
314
|
-
const itemSchema = schema.items;
|
|
315
|
-
const itemType = swaggerTypeToTsType(itemSchema, schemas);
|
|
316
|
-
if (itemSchema?.$ref &&
|
|
317
|
-
schemas &&
|
|
318
|
-
typeof itemSchema.$ref === 'string' &&
|
|
319
|
-
itemSchema.$ref.startsWith('#/')) {
|
|
320
|
-
const refName = itemSchema.$ref.split('/').pop();
|
|
321
|
-
const referencedSchema = refName ? schemas[refName] : undefined;
|
|
322
|
-
if (referencedSchema?.type === 'array') {
|
|
323
|
-
baseType = itemType;
|
|
324
|
-
}
|
|
325
|
-
else {
|
|
326
|
-
baseType = `${itemType}[]`;
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
else {
|
|
330
|
-
baseType = `${itemType}[]`;
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
// 处理对象类型
|
|
334
|
-
else if (schema.type === 'object') {
|
|
335
|
-
if (schema.properties) {
|
|
336
|
-
const properties = Object.entries(schema.properties)
|
|
337
|
-
.map(([key, value]) => {
|
|
338
|
-
const optional = schema.required?.includes(key) ? '' : '?';
|
|
339
|
-
let type = swaggerTypeToTsType(value, schemas);
|
|
340
|
-
if (optional === '?')
|
|
341
|
-
type = stripNullFromUnion(type);
|
|
342
|
-
return ` ${key}${optional}: ${type};`;
|
|
343
|
-
})
|
|
344
|
-
.join('\n');
|
|
345
|
-
baseType = `{\n${properties}\n}`;
|
|
346
|
-
}
|
|
347
|
-
else {
|
|
348
|
-
baseType = 'Record<string, any>';
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
|
-
// 处理基本类型
|
|
352
|
-
else {
|
|
353
|
-
switch (schema.type) {
|
|
354
|
-
case 'integer':
|
|
355
|
-
case 'number':
|
|
356
|
-
baseType = 'number';
|
|
357
|
-
break;
|
|
358
|
-
case 'string':
|
|
359
|
-
if (schema.enum) {
|
|
360
|
-
baseType = schema.enum.map((value) => `'${value}'`).join(' | ');
|
|
361
|
-
}
|
|
362
|
-
else {
|
|
363
|
-
baseType = 'string';
|
|
364
|
-
}
|
|
365
|
-
break;
|
|
366
|
-
case 'boolean':
|
|
367
|
-
baseType = 'boolean';
|
|
368
|
-
break;
|
|
369
|
-
case 'file':
|
|
370
|
-
baseType = 'File';
|
|
371
|
-
break;
|
|
372
|
-
case 'null': // Add this
|
|
373
|
-
baseType = 'null';
|
|
374
|
-
break;
|
|
375
|
-
default:
|
|
376
|
-
baseType = 'any';
|
|
377
|
-
break;
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
// 处理 nullable 属性
|
|
381
|
-
if (schema.nullable === true) {
|
|
382
|
-
if (baseType === 'any')
|
|
383
|
-
return 'any';
|
|
384
|
-
if (baseType.includes('null'))
|
|
385
|
-
return baseType;
|
|
386
|
-
return `${baseType} | null`;
|
|
387
|
-
}
|
|
388
|
-
return baseType;
|
|
389
|
-
}
|
|
390
|
-
/**
|
|
391
|
-
* 从Swagger参数生成TypeScript参数类型
|
|
392
|
-
* @param parameters Swagger参数数组
|
|
393
|
-
* @returns TypeScript参数类型定义
|
|
394
|
-
*/
|
|
395
|
-
function generateParameterTypes(parameters) {
|
|
396
|
-
if (!parameters || parameters.length === 0) {
|
|
397
|
-
return '';
|
|
398
|
-
}
|
|
399
|
-
const queryParams = parameters.filter((p) => p.in === 'query');
|
|
400
|
-
const pathParams = parameters.filter((p) => p.in === 'path');
|
|
401
|
-
const bodyParams = parameters.filter((p) => p.in === 'body');
|
|
402
|
-
const formParams = parameters.filter((p) => p.in === 'formData');
|
|
403
|
-
const types = [];
|
|
404
|
-
// 路径参数
|
|
405
|
-
if (pathParams.length > 0) {
|
|
406
|
-
const pathType = pathParams
|
|
407
|
-
.map((p) => `${p.name}: ${swaggerTypeToTsType({ type: p.type || 'string' })}`)
|
|
408
|
-
.join(', ');
|
|
409
|
-
types.push(`pathParams: { ${pathType} }`);
|
|
410
|
-
}
|
|
411
|
-
// 查询参数
|
|
412
|
-
if (queryParams.length > 0) {
|
|
413
|
-
const queryType = queryParams
|
|
414
|
-
.map((p) => {
|
|
415
|
-
const optional = p.required ? '' : '?';
|
|
416
|
-
return `${p.name}${optional}: ${swaggerTypeToTsType({ type: p.type || 'string' })}`;
|
|
417
|
-
})
|
|
418
|
-
.join(', ');
|
|
419
|
-
types.push(`queryParams${queryParams.every((p) => !p.required) ? '?' : ''}: { ${queryType} }`);
|
|
420
|
-
}
|
|
421
|
-
// 请求体参数
|
|
422
|
-
if (bodyParams.length > 0) {
|
|
423
|
-
const bodyParam = bodyParams[0];
|
|
424
|
-
const bodyType = swaggerTypeToTsType(bodyParam.schema);
|
|
425
|
-
types.push(`data: ${bodyType}`);
|
|
426
|
-
}
|
|
427
|
-
// 表单参数
|
|
428
|
-
if (formParams.length > 0) {
|
|
429
|
-
const formType = formParams
|
|
430
|
-
.map((p) => {
|
|
431
|
-
const optional = p.required ? '' : '?';
|
|
432
|
-
return `${p.name}${optional}: ${swaggerTypeToTsType({ type: p.type || 'string' })}`;
|
|
433
|
-
})
|
|
434
|
-
.join(', ');
|
|
435
|
-
types.push(`data: { ${formType} }`);
|
|
436
|
-
}
|
|
437
|
-
return types.join(', ');
|
|
438
|
-
}
|
|
439
|
-
/**
|
|
440
|
-
* 确保目录存在,如果不存在则创建
|
|
441
|
-
* @param dirPath 目录路径
|
|
442
|
-
*/
|
|
443
|
-
function ensureDirectoryExists(dirPath) {
|
|
444
|
-
if (!fs.existsSync(dirPath)) {
|
|
445
|
-
fs.mkdirSync(dirPath, { recursive: true });
|
|
446
|
-
}
|
|
447
|
-
}
|
|
448
|
-
/**
|
|
449
|
-
* 删除目录及其所有内容
|
|
450
|
-
* @param dirPath 目录路径
|
|
451
|
-
*/
|
|
452
|
-
function removeDirectory(dirPath) {
|
|
453
|
-
if (fs.existsSync(dirPath)) {
|
|
454
|
-
fs.rmSync(dirPath, { recursive: true, force: true });
|
|
455
|
-
}
|
|
456
|
-
}
|
|
457
|
-
/**
|
|
458
|
-
* 读取Swagger文档
|
|
459
|
-
* @param input 文件路径或URL
|
|
460
|
-
* @returns Swagger文档对象
|
|
461
|
-
*/
|
|
462
|
-
async function loadSwaggerDocument(input) {
|
|
463
|
-
try {
|
|
464
|
-
if (input.startsWith('http://') || input.startsWith('https://')) {
|
|
465
|
-
const { data } = await axios_1.default.get(input);
|
|
466
|
-
console.log('Loaded from URL:', input);
|
|
467
|
-
if (data.components?.schemas) {
|
|
468
|
-
console.log('Schemas count:', Object.keys(data.components.schemas).length);
|
|
469
|
-
}
|
|
470
|
-
else {
|
|
471
|
-
console.log('No schemas in loaded data');
|
|
472
|
-
}
|
|
473
|
-
return data;
|
|
474
|
-
}
|
|
475
|
-
else {
|
|
476
|
-
// 从文件加载
|
|
477
|
-
const content = fs.readFileSync(input, 'utf-8');
|
|
478
|
-
return JSON.parse(content);
|
|
479
|
-
}
|
|
480
|
-
}
|
|
481
|
-
catch (error) {
|
|
482
|
-
throw new Error(`Failed to load Swagger document from ${input}: ${error}`);
|
|
483
|
-
}
|
|
484
|
-
}
|
|
485
|
-
/**
|
|
486
|
-
* 写入文件
|
|
487
|
-
* @param filePath 文件路径
|
|
488
|
-
* @param content 文件内容
|
|
489
|
-
*/
|
|
490
|
-
function writeFile(filePath, content) {
|
|
491
|
-
const dir = path.dirname(filePath);
|
|
492
|
-
ensureDirectoryExists(dir);
|
|
493
|
-
fs.writeFileSync(filePath, content, 'utf-8');
|
|
494
|
-
}
|
|
495
|
-
/**
|
|
496
|
-
* 生成接口注释
|
|
497
|
-
* @param operation Swagger操作对象
|
|
498
|
-
* @param parameters 参数列表
|
|
499
|
-
* @returns 注释字符串
|
|
500
|
-
*/
|
|
501
|
-
function generateApiComment(operation, parameters) {
|
|
502
|
-
const comments = ['/**'];
|
|
503
|
-
if (operation.summary) {
|
|
504
|
-
comments.push(` * ${operation.summary}`);
|
|
505
|
-
}
|
|
506
|
-
if (operation.description && operation.description !== operation.summary) {
|
|
507
|
-
comments.push(` * ${operation.description}`);
|
|
508
|
-
}
|
|
509
|
-
if (parameters && parameters.length > 0) {
|
|
510
|
-
// 收集不同类型的参数
|
|
511
|
-
const queryParams = parameters.filter((p) => p.in === 'query');
|
|
512
|
-
const pathParams = parameters.filter((p) => p.in === 'path');
|
|
513
|
-
const bodyParams = parameters.filter((p) => p.in === 'body');
|
|
514
|
-
const formParams = parameters.filter((p) => p.in === 'formData');
|
|
515
|
-
const hasParams = queryParams.length > 0 || pathParams.length > 0;
|
|
516
|
-
const hasData = bodyParams.length > 0 || formParams.length > 0;
|
|
517
|
-
if (hasParams || hasData) {
|
|
518
|
-
comments.push(' *');
|
|
519
|
-
// 如果有查询参数或路径参数,添加params注释
|
|
520
|
-
if (hasParams) {
|
|
521
|
-
const paramDescriptions = [...pathParams, ...queryParams]
|
|
522
|
-
.map((p) => p.description || '')
|
|
523
|
-
.filter((desc) => desc)
|
|
524
|
-
.join(', ');
|
|
525
|
-
const description = paramDescriptions || '请求参数';
|
|
526
|
-
comments.push(` * @param params ${description}`);
|
|
527
|
-
}
|
|
528
|
-
// 如果有请求体参数,添加data注释
|
|
529
|
-
if (hasData) {
|
|
530
|
-
const dataParam = bodyParams[0] || formParams[0];
|
|
531
|
-
const description = dataParam?.description || '请求数据';
|
|
532
|
-
comments.push(` * @param data ${description}`);
|
|
533
|
-
}
|
|
534
|
-
// 添加config参数注释
|
|
535
|
-
comments.push(` * @param config 可选的请求配置`);
|
|
536
|
-
}
|
|
537
|
-
}
|
|
538
|
-
if (operation.deprecated) {
|
|
539
|
-
comments.push(' * @deprecated');
|
|
540
|
-
}
|
|
541
|
-
comments.push(' */');
|
|
542
|
-
return comments.join('\n');
|
|
543
|
-
}
|
|
544
|
-
/**
|
|
545
|
-
* 清理文件名,移除非法字符
|
|
546
|
-
* @param filename 文件名
|
|
547
|
-
* @returns 清理后的文件名
|
|
548
|
-
*/
|
|
549
|
-
function sanitizeFilename(filename) {
|
|
550
|
-
return filename.replace(/[<>:"/\\|?*]/g, '-').replace(/\s+/g, '-');
|
|
551
|
-
}
|
|
552
|
-
/**
|
|
553
|
-
* 获取响应类型
|
|
554
|
-
* @param responses Swagger响应对象
|
|
555
|
-
* @returns TypeScript类型字符串
|
|
556
|
-
*/
|
|
557
|
-
function getResponseType(responses) {
|
|
558
|
-
if (!responses) {
|
|
559
|
-
return 'any';
|
|
560
|
-
}
|
|
561
|
-
// 优先获取200响应
|
|
562
|
-
const successResponse = responses['200'] || responses['201'] || responses['default'];
|
|
563
|
-
if (!successResponse) {
|
|
564
|
-
return 'any';
|
|
565
|
-
}
|
|
566
|
-
// 支持OpenAPI 3.0格式 (content.application/json.schema)
|
|
567
|
-
if (successResponse.content &&
|
|
568
|
-
successResponse.content['application/json'] &&
|
|
569
|
-
successResponse.content['application/json'].schema) {
|
|
570
|
-
return swaggerTypeToTsType(successResponse.content['application/json'].schema);
|
|
571
|
-
}
|
|
572
|
-
// 支持Swagger 2.0格式 (直接schema)
|
|
573
|
-
if (successResponse.schema) {
|
|
574
|
-
return swaggerTypeToTsType(successResponse.schema);
|
|
575
|
-
}
|
|
576
|
-
return 'any';
|
|
577
|
-
}
|
|
578
|
-
function sanitizeTypeName(name) {
|
|
579
|
-
if (!name)
|
|
580
|
-
return name;
|
|
581
|
-
// 1. 替换非法字符(包括点号)为下划线
|
|
582
|
-
const replaced = name.replace(/[^a-zA-Z0-9_]/g, '_');
|
|
583
|
-
// 2. 转换为 PascalCase
|
|
584
|
-
// 使用现有的 toPascalCase,它能处理下划线
|
|
585
|
-
return toPascalCase(replaced);
|
|
586
|
-
}
|
|
17
|
+
__exportStar(require("./naming"), exports);
|
|
18
|
+
__exportStar(require("./type"), exports);
|
|
19
|
+
__exportStar(require("./file"), exports);
|
|
20
|
+
__exportStar(require("./comment"), exports);
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 将路径转换为小驼峰命名的函数名
|
|
3
|
+
* @param method HTTP方法
|
|
4
|
+
* @param path 接口路径
|
|
5
|
+
* @returns 小驼峰命名的函数名
|
|
6
|
+
*/
|
|
7
|
+
export declare function pathToFunctionName(method: string, path: string): string;
|
|
8
|
+
/**
|
|
9
|
+
* 将字符串转换为kebab-case
|
|
10
|
+
* @param str 输入字符串
|
|
11
|
+
* @returns kebab-case字符串
|
|
12
|
+
*/
|
|
13
|
+
export declare function toKebabCase(str: string): string;
|
|
14
|
+
/**
|
|
15
|
+
* 将字符串转换为PascalCase
|
|
16
|
+
* @param str 输入字符串
|
|
17
|
+
* @returns PascalCase字符串
|
|
18
|
+
*/
|
|
19
|
+
export declare function toPascalCase(str: string): string;
|
|
20
|
+
/**
|
|
21
|
+
* 将字符串转换为camelCase
|
|
22
|
+
* @param str 输入字符串
|
|
23
|
+
* @returns camelCase字符串
|
|
24
|
+
*/
|
|
25
|
+
export declare function toCamelCase(str: string): string;
|
|
26
|
+
/**
|
|
27
|
+
* 从方法名中移除指定的前缀
|
|
28
|
+
* @param methodName 方法名
|
|
29
|
+
* @param prefixes 需要移除的前缀数组
|
|
30
|
+
* @returns 移除前缀后的方法名
|
|
31
|
+
*/
|
|
32
|
+
export declare function stripMethodNamePrefixes(methodName: string, prefixes?: string[]): string;
|
|
33
|
+
/**
|
|
34
|
+
* 从函数名中移除 HTTP method 后缀
|
|
35
|
+
* @param functionName 函数名
|
|
36
|
+
* @param method HTTP 方法
|
|
37
|
+
* @returns 移除后缀后的函数名
|
|
38
|
+
*/
|
|
39
|
+
export declare function removeMethodSuffix(functionName: string, method: string): string;
|
|
40
|
+
/**
|
|
41
|
+
* 清理文件名,移除非法字符
|
|
42
|
+
* @param filename 文件名
|
|
43
|
+
* @returns 清理后的文件名
|
|
44
|
+
*/
|
|
45
|
+
export declare function sanitizeFilename(filename: string): string;
|
|
46
|
+
/**
|
|
47
|
+
* 清理类型名称并转换为 PascalCase
|
|
48
|
+
* @param name 类型名称
|
|
49
|
+
* @returns 清理后的类型名称
|
|
50
|
+
*/
|
|
51
|
+
export declare function sanitizeTypeName(name: string): string;
|