swagger2api-v3 1.1.4 → 1.1.6
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 +22 -35
- package/dist/cli/index.js +34 -72
- package/dist/core/parser.js +6 -2
- package/dist/index.js +15 -10
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +91 -16
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
English | [中文](./README_CN.md)
|
|
4
4
|
|
|
5
|
-
A powerful command-line tool for automatically generating TypeScript interface code from
|
|
5
|
+
A powerful command-line tool for automatically generating TypeScript or JavaScript interface code from OpenAPI 3.0 documentation.
|
|
6
6
|
|
|
7
7
|
## ✨ Features
|
|
8
8
|
|
|
@@ -33,36 +33,25 @@ npx swagger2api-v3 init
|
|
|
33
33
|
|
|
34
34
|
### 2. Configuration File Description
|
|
35
35
|
|
|
36
|
-
The tool
|
|
36
|
+
The tool generates a `.swagger.config.json` configuration file:
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
38
|
+
```json
|
|
39
|
+
{
|
|
40
|
+
"input": "https://petstore.swagger.io/v2/swagger.json",
|
|
41
|
+
"output": "./src/api",
|
|
42
|
+
"importTemplate": "import { request } from '@/utils/request';",
|
|
43
|
+
"generator": "typescript",
|
|
44
|
+
"requestStyle": "generic",
|
|
45
|
+
"groupByTags": true,
|
|
46
|
+
"overwrite": true,
|
|
47
|
+
"prefix": "",
|
|
48
|
+
"lint": "prettier --write",
|
|
49
|
+
"methodNameIgnorePrefix": [],
|
|
50
|
+
"addMethodSuffix": true,
|
|
51
|
+
"options": {
|
|
52
|
+
"addComments": true
|
|
52
53
|
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
module.exports = config;
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
**ES Module Environment** (`"type": "module"`):
|
|
59
|
-
|
|
60
|
-
```javascript
|
|
61
|
-
const config = {
|
|
62
|
-
// ... same configuration
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
export default config;
|
|
54
|
+
}
|
|
66
55
|
```
|
|
67
56
|
|
|
68
57
|
### 3. Generate Interface Code
|
|
@@ -226,12 +215,10 @@ Add to `package.json`:
|
|
|
226
215
|
|
|
227
216
|
Support automatic execution of formatting commands after generation:
|
|
228
217
|
|
|
229
|
-
```
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
lint: 'prettier --write' // or 'eslint --fix', etc.
|
|
234
|
-
};
|
|
218
|
+
```json
|
|
219
|
+
{
|
|
220
|
+
"lint": "prettier --write"
|
|
221
|
+
}
|
|
235
222
|
```
|
|
236
223
|
|
|
237
224
|
## 🤝 Contributing
|
package/dist/cli/index.js
CHANGED
|
@@ -50,7 +50,7 @@ program
|
|
|
50
50
|
.command('generate')
|
|
51
51
|
.alias('gen')
|
|
52
52
|
.description('根据配置文件生成 API 接口')
|
|
53
|
-
.option('-c, --config <path>', '配置文件路径', '.swagger.config.
|
|
53
|
+
.option('-c, --config <path>', '配置文件路径', '.swagger.config.json')
|
|
54
54
|
.option('-i, --input <path>', 'Swagger JSON 文件路径或 URL')
|
|
55
55
|
.option('-o, --output <path>', '输出目录')
|
|
56
56
|
.option('--no-types', '不生成类型文件')
|
|
@@ -92,79 +92,31 @@ program
|
|
|
92
92
|
.description('初始化配置文件')
|
|
93
93
|
.option('-f, --force', '强制覆盖已存在的配置文件')
|
|
94
94
|
.action(async (options) => {
|
|
95
|
-
const configPath = path.resolve(process.cwd(), '.swagger.config.
|
|
95
|
+
const configPath = path.resolve(process.cwd(), '.swagger.config.json');
|
|
96
96
|
if (fs.existsSync(configPath) && !options.force) {
|
|
97
97
|
console.error('❌ 配置文件已存在,使用 --force 参数强制覆盖');
|
|
98
98
|
process.exit(1);
|
|
99
99
|
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
100
|
+
const config = {
|
|
101
|
+
input: 'http://localhost:3000/admin/docs/json',
|
|
102
|
+
output: './src/api',
|
|
103
|
+
importTemplate: "import { request } from '@/utils/request';",
|
|
104
|
+
generator: 'typescript',
|
|
105
|
+
requestStyle: 'generic',
|
|
106
|
+
groupByTags: true,
|
|
107
|
+
overwrite: true,
|
|
108
|
+
prefix: '',
|
|
109
|
+
lint: 'prettier --write',
|
|
110
|
+
methodNameIgnorePrefix: [],
|
|
111
|
+
addMethodSuffix: true,
|
|
112
|
+
options: {
|
|
113
|
+
addComments: true
|
|
108
114
|
}
|
|
109
|
-
|
|
110
|
-
console.warn('⚠️ 无法读取package.json,使用默认ES Module格式');
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
const configContent = `/**
|
|
114
|
-
* Swagger2API 配置文件
|
|
115
|
-
* 用于配置从 Swagger JSON 生成前端接口的参数
|
|
116
|
-
*/
|
|
117
|
-
const config = {
|
|
118
|
-
// Swagger JSON 文件路径或 URL
|
|
119
|
-
input: 'http://localhost:3000/admin/docs/json',
|
|
120
|
-
|
|
121
|
-
// 输出目录
|
|
122
|
-
output: './src/api',
|
|
123
|
-
|
|
124
|
-
// request 导入路径模板
|
|
125
|
-
importTemplate: "import { request } from '@/utils/request';",
|
|
126
|
-
|
|
127
|
-
// 生成器类型
|
|
128
|
-
generator: 'typescript', // 可选 'javascript'(JS 模式输出 .js 文件且不生成类型文件)
|
|
129
|
-
|
|
130
|
-
// 请求调用风格:'method' 使用 request.get/post;'generic' 使用 request({ method })
|
|
131
|
-
requestStyle: 'generic',
|
|
132
|
-
|
|
133
|
-
// 按标签分组生成文件
|
|
134
|
-
groupByTags: true,
|
|
135
|
-
|
|
136
|
-
// 是否覆盖更新,默认为true。为true时会先删除输出目录下的所有文件
|
|
137
|
-
overwrite: true,
|
|
138
|
-
|
|
139
|
-
// 接口路径公共前缀,默认为空字符串
|
|
140
|
-
prefix: '',
|
|
141
|
-
|
|
142
|
-
// 代码格式化命令(可选)
|
|
143
|
-
lint: 'prettier --write',
|
|
144
|
-
|
|
145
|
-
// 生成方法名时需要忽略的前缀(可选)
|
|
146
|
-
// 例如:配置 ['api', 'auth'] 后,apiGetName 会变成 getName,authUserInfo 会变成 userInfo
|
|
147
|
-
// 如果方法名是 apiAuthGetName,会依次移除所有匹配的前缀,最终变成 getName
|
|
148
|
-
methodNameIgnorePrefix: [],
|
|
149
|
-
|
|
150
|
-
// 是否在生成的方法名中添加 HTTP method 后缀,默认为 true
|
|
151
|
-
// true: userListPost, userDetailGet
|
|
152
|
-
// false: userList, userDetail
|
|
153
|
-
addMethodSuffix: true,
|
|
154
|
-
|
|
155
|
-
// 生成选项
|
|
156
|
-
options: {
|
|
157
|
-
// 是否添加注释
|
|
158
|
-
addComments: true
|
|
159
|
-
}
|
|
160
|
-
};
|
|
161
|
-
|
|
162
|
-
${isESModule ? 'export default config;' : 'module.exports = config;'}
|
|
163
|
-
`;
|
|
115
|
+
};
|
|
164
116
|
try {
|
|
165
|
-
fs.writeFileSync(configPath,
|
|
117
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf-8');
|
|
166
118
|
console.log('✅ 配置文件已创建:', configPath);
|
|
167
|
-
console.log('💡 请根据需要修改配置文件,然后运行 swagger2api generate');
|
|
119
|
+
console.log('💡 请根据需要修改配置文件,然后运行 swagger2api-v3 generate');
|
|
168
120
|
}
|
|
169
121
|
catch (error) {
|
|
170
122
|
console.error('❌ 创建配置文件失败:', error);
|
|
@@ -175,12 +127,16 @@ ${isESModule ? 'export default config;' : 'module.exports = config;'}
|
|
|
175
127
|
program
|
|
176
128
|
.command('validate')
|
|
177
129
|
.description('验证配置文件')
|
|
178
|
-
.option('-c, --config <path>', '配置文件路径', '.swagger.config.
|
|
130
|
+
.option('-c, --config <path>', '配置文件路径', '.swagger.config.json')
|
|
179
131
|
.action(async (options) => {
|
|
180
132
|
const configPath = path.resolve(process.cwd(), options.config);
|
|
181
133
|
try {
|
|
182
|
-
|
|
183
|
-
|
|
134
|
+
if (!fs.existsSync(configPath)) {
|
|
135
|
+
console.error(`❌ 找不到配置文件: ${configPath}`);
|
|
136
|
+
process.exit(1);
|
|
137
|
+
}
|
|
138
|
+
const configContent = fs.readFileSync(configPath, 'utf-8');
|
|
139
|
+
const config = JSON.parse(configContent);
|
|
184
140
|
const { Swagger2API } = await Promise.resolve().then(() => __importStar(require('../index')));
|
|
185
141
|
const swagger2api = new Swagger2API(config);
|
|
186
142
|
if (swagger2api.validateConfig()) {
|
|
@@ -200,7 +156,13 @@ program
|
|
|
200
156
|
}
|
|
201
157
|
}
|
|
202
158
|
catch (error) {
|
|
203
|
-
|
|
159
|
+
if (error instanceof SyntaxError) {
|
|
160
|
+
console.error(`❌ 配置文件 JSON 格式错误: ${configPath}`);
|
|
161
|
+
console.error('错误详情:', error.message);
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
console.error('❌ 配置文件验证失败:', error);
|
|
165
|
+
}
|
|
204
166
|
process.exit(1);
|
|
205
167
|
}
|
|
206
168
|
});
|
|
@@ -208,7 +170,7 @@ program
|
|
|
208
170
|
program
|
|
209
171
|
.command('run')
|
|
210
172
|
.description('运行生成器(generate 命令的别名)')
|
|
211
|
-
.option('-c, --config <path>', '配置文件路径', '.swagger.config.
|
|
173
|
+
.option('-c, --config <path>', '配置文件路径', '.swagger.config.json')
|
|
212
174
|
.action(async (options) => {
|
|
213
175
|
try {
|
|
214
176
|
await (0, index_1.generateFromConfig)(options.config);
|
package/dist/core/parser.js
CHANGED
|
@@ -180,7 +180,9 @@ class SwaggerParser {
|
|
|
180
180
|
const properties = Object.entries(schema.properties)
|
|
181
181
|
.map(([key, value]) => {
|
|
182
182
|
const optional = schema.required?.includes(key) ? '' : '?';
|
|
183
|
-
|
|
183
|
+
let type = (0, utils_1.swaggerTypeToTsType)(value, allSchemas);
|
|
184
|
+
if (optional === '?')
|
|
185
|
+
type = (0, utils_1.stripNullFromUnion)(type);
|
|
184
186
|
const comment = value.description
|
|
185
187
|
? ` /** ${value.description} */`
|
|
186
188
|
: '';
|
|
@@ -203,7 +205,9 @@ class SwaggerParser {
|
|
|
203
205
|
// 优先使用 x-enum-varnames 或 x-enumNames 扩展字段
|
|
204
206
|
if ((schema['x-enum-varnames'] && schema['x-enum-varnames'][index]) ||
|
|
205
207
|
(schema['x-enumNames'] && schema['x-enumNames'][index])) {
|
|
206
|
-
key =
|
|
208
|
+
key =
|
|
209
|
+
schema['x-enum-varnames']?.[index] ||
|
|
210
|
+
schema['x-enumNames']?.[index];
|
|
207
211
|
}
|
|
208
212
|
else if (/^\d+$/.test(value)) {
|
|
209
213
|
// 对于数字枚举,使用 VALUE_ 前缀
|
package/dist/index.js
CHANGED
|
@@ -40,6 +40,7 @@ exports.CodeGenerator = exports.SwaggerParser = exports.Swagger2API = void 0;
|
|
|
40
40
|
exports.generateFromConfig = generateFromConfig;
|
|
41
41
|
exports.generate = generate;
|
|
42
42
|
const path = __importStar(require("path"));
|
|
43
|
+
const fs = __importStar(require("fs"));
|
|
43
44
|
const parser_1 = require("./core/parser");
|
|
44
45
|
const generator_1 = require("./core/generator");
|
|
45
46
|
const utils_1 = require("./utils");
|
|
@@ -119,15 +120,19 @@ exports.Swagger2API = Swagger2API;
|
|
|
119
120
|
* @param configPath 配置文件路径
|
|
120
121
|
*/
|
|
121
122
|
async function generateFromConfig(configPath) {
|
|
122
|
-
const configFile = configPath || '.swagger.config.
|
|
123
|
+
const configFile = configPath || '.swagger.config.json';
|
|
123
124
|
const fullPath = path.resolve(process.cwd(), configFile);
|
|
124
125
|
try {
|
|
125
126
|
let config;
|
|
126
|
-
//
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
127
|
+
// 读取并解析 JSON 配置文件
|
|
128
|
+
if (!fs.existsSync(fullPath)) {
|
|
129
|
+
console.error(`❌ 找不到配置文件: ${fullPath}`);
|
|
130
|
+
console.error('请确保配置文件存在并且路径正确');
|
|
131
|
+
console.error('提示: 运行 swagger2api-v3 init 来创建配置文件');
|
|
132
|
+
process.exit(1);
|
|
133
|
+
}
|
|
134
|
+
const configContent = fs.readFileSync(fullPath, 'utf-8');
|
|
135
|
+
config = JSON.parse(configContent);
|
|
131
136
|
const swagger2api = new Swagger2API(config);
|
|
132
137
|
if (!swagger2api.validateConfig()) {
|
|
133
138
|
process.exit(1);
|
|
@@ -135,10 +140,10 @@ async function generateFromConfig(configPath) {
|
|
|
135
140
|
await swagger2api.generate();
|
|
136
141
|
}
|
|
137
142
|
catch (error) {
|
|
138
|
-
if (error instanceof
|
|
139
|
-
error
|
|
140
|
-
console.error(
|
|
141
|
-
console.error('
|
|
143
|
+
if (error instanceof SyntaxError) {
|
|
144
|
+
console.error(`❌ 配置文件 JSON 格式错误: ${fullPath}`);
|
|
145
|
+
console.error('请检查 JSON 语法是否正确');
|
|
146
|
+
console.error('错误详情:', error.message);
|
|
142
147
|
}
|
|
143
148
|
else {
|
|
144
149
|
console.error('❌ 加载配置文件失败:', error);
|
package/dist/utils/index.d.ts
CHANGED
|
@@ -41,6 +41,7 @@ export declare function stripMethodNamePrefixes(methodName: string, prefixes?: s
|
|
|
41
41
|
* @returns 移除后缀后的函数名
|
|
42
42
|
*/
|
|
43
43
|
export declare function removeMethodSuffix(functionName: string, method: string): string;
|
|
44
|
+
export declare function stripNullFromUnion(typeStr: string): string;
|
|
44
45
|
/**
|
|
45
46
|
* 将Swagger类型转换为TypeScript类型
|
|
46
47
|
* @param schema Swagger模式
|
package/dist/utils/index.js
CHANGED
|
@@ -42,6 +42,7 @@ exports.toPascalCase = toPascalCase;
|
|
|
42
42
|
exports.toCamelCase = toCamelCase;
|
|
43
43
|
exports.stripMethodNamePrefixes = stripMethodNamePrefixes;
|
|
44
44
|
exports.removeMethodSuffix = removeMethodSuffix;
|
|
45
|
+
exports.stripNullFromUnion = stripNullFromUnion;
|
|
45
46
|
exports.swaggerTypeToTsType = swaggerTypeToTsType;
|
|
46
47
|
exports.generateParameterTypes = generateParameterTypes;
|
|
47
48
|
exports.ensureDirectoryExists = ensureDirectoryExists;
|
|
@@ -165,6 +166,49 @@ function removeMethodSuffix(functionName, method) {
|
|
|
165
166
|
}
|
|
166
167
|
return functionName;
|
|
167
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
|
+
}
|
|
168
212
|
/**
|
|
169
213
|
* 将Swagger类型转换为TypeScript类型
|
|
170
214
|
* @param schema Swagger模式
|
|
@@ -190,7 +234,7 @@ function swaggerTypeToTsType(schema, schemas) {
|
|
|
190
234
|
// 这里假设泛型参数是 properties 中的第一个属性
|
|
191
235
|
const propertyTypes = [];
|
|
192
236
|
for (const [propName, propSchema] of Object.entries(secondSchema.properties)) {
|
|
193
|
-
const propType = swaggerTypeToTsType(propSchema);
|
|
237
|
+
const propType = swaggerTypeToTsType(propSchema, schemas);
|
|
194
238
|
propertyTypes.push(propType);
|
|
195
239
|
}
|
|
196
240
|
// 如果只有一个属性,直接作为泛型参数
|
|
@@ -202,7 +246,9 @@ function swaggerTypeToTsType(schema, schemas) {
|
|
|
202
246
|
const combinedType = `{ ${Object.entries(secondSchema.properties)
|
|
203
247
|
.map(([key, value]) => {
|
|
204
248
|
const optional = secondSchema.required?.includes(key) ? '' : '?';
|
|
205
|
-
|
|
249
|
+
let type = swaggerTypeToTsType(value, schemas);
|
|
250
|
+
if (optional === '?')
|
|
251
|
+
type = stripNullFromUnion(type);
|
|
206
252
|
return `${key}${optional}: ${type}`;
|
|
207
253
|
})
|
|
208
254
|
.join('; ')} }`;
|
|
@@ -226,21 +272,25 @@ function swaggerTypeToTsType(schema, schemas) {
|
|
|
226
272
|
}
|
|
227
273
|
// 处理 anyOf 或 oneOf
|
|
228
274
|
else if (schema.anyOf || schema.oneOf) {
|
|
229
|
-
const types = (schema.anyOf || schema.oneOf)
|
|
230
|
-
.map((s) => {
|
|
275
|
+
const types = (schema.anyOf || schema.oneOf).map((s) => {
|
|
231
276
|
// 特殊处理 type: 'null'
|
|
232
277
|
if (s.type === 'null')
|
|
233
278
|
return 'null';
|
|
234
|
-
return swaggerTypeToTsType(s);
|
|
235
|
-
})
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
if (uniqueTypes.length > 0) {
|
|
240
|
-
baseType = uniqueTypes.join(' | ');
|
|
279
|
+
return swaggerTypeToTsType(s, schemas);
|
|
280
|
+
});
|
|
281
|
+
// 如果包含 any,则直接返回 any
|
|
282
|
+
if (types.includes('any')) {
|
|
283
|
+
baseType = 'any';
|
|
241
284
|
}
|
|
242
285
|
else {
|
|
243
|
-
|
|
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
|
+
}
|
|
244
294
|
}
|
|
245
295
|
}
|
|
246
296
|
// 处理引用类型
|
|
@@ -248,7 +298,10 @@ function swaggerTypeToTsType(schema, schemas) {
|
|
|
248
298
|
const refName = schema.$ref.split('/').pop();
|
|
249
299
|
baseType = sanitizeTypeName(refName || 'any');
|
|
250
300
|
// 如果提供了 schemas 上下文,检查被引用的 schema 是否是数组类型
|
|
251
|
-
if (schemas &&
|
|
301
|
+
if (schemas &&
|
|
302
|
+
refName &&
|
|
303
|
+
typeof schema.$ref === 'string' &&
|
|
304
|
+
schema.$ref.startsWith('#/')) {
|
|
252
305
|
const referencedSchema = schemas[refName];
|
|
253
306
|
if (referencedSchema && referencedSchema.type === 'array') {
|
|
254
307
|
// 被引用的 schema 是数组类型,添加 []
|
|
@@ -258,8 +311,24 @@ function swaggerTypeToTsType(schema, schemas) {
|
|
|
258
311
|
}
|
|
259
312
|
// 处理数组类型
|
|
260
313
|
else if (schema.type === 'array') {
|
|
261
|
-
const
|
|
262
|
-
|
|
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
|
+
}
|
|
263
332
|
}
|
|
264
333
|
// 处理对象类型
|
|
265
334
|
else if (schema.type === 'object') {
|
|
@@ -267,7 +336,9 @@ function swaggerTypeToTsType(schema, schemas) {
|
|
|
267
336
|
const properties = Object.entries(schema.properties)
|
|
268
337
|
.map(([key, value]) => {
|
|
269
338
|
const optional = schema.required?.includes(key) ? '' : '?';
|
|
270
|
-
|
|
339
|
+
let type = swaggerTypeToTsType(value, schemas);
|
|
340
|
+
if (optional === '?')
|
|
341
|
+
type = stripNullFromUnion(type);
|
|
271
342
|
return ` ${key}${optional}: ${type};`;
|
|
272
343
|
})
|
|
273
344
|
.join('\n');
|
|
@@ -308,6 +379,10 @@ function swaggerTypeToTsType(schema, schemas) {
|
|
|
308
379
|
}
|
|
309
380
|
// 处理 nullable 属性
|
|
310
381
|
if (schema.nullable === true) {
|
|
382
|
+
if (baseType === 'any')
|
|
383
|
+
return 'any';
|
|
384
|
+
if (baseType.includes('null'))
|
|
385
|
+
return baseType;
|
|
311
386
|
return `${baseType} | null`;
|
|
312
387
|
}
|
|
313
388
|
return baseType;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "swagger2api-v3",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.6",
|
|
4
4
|
"description": "A command-line tool for generating TypeScript API interfaces from Swagger (OAS 3.0) documentation",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"prebuild": "npm run clean",
|
|
24
24
|
"start": "node dist/cli/index.js",
|
|
25
25
|
"dev": "npm run build && npm start",
|
|
26
|
-
"lint": "prettier --write",
|
|
26
|
+
"lint": "prettier --write .",
|
|
27
27
|
"generate": "npm run build && node dist/cli/index.js generate",
|
|
28
28
|
"init": "npm run build && node dist/cli/index.js init",
|
|
29
29
|
"validate": "npm run build && node dist/cli/index.js validate",
|