swagger2api-v3 1.1.9 → 1.1.11
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 +5 -3
- package/dist/.swagger2api.schema.json +6 -2
- package/dist/cli/index.js +22 -21
- package/dist/config/validator.js +94 -9
- package/dist/core/generator.d.ts +83 -11
- package/dist/core/generator.js +295 -94
- package/dist/core/parser.d.ts +20 -16
- package/dist/core/parser.js +72 -103
- package/dist/core/query-parameter-generator.d.ts +26 -0
- package/dist/core/query-parameter-generator.js +114 -0
- package/dist/core/type-generator.d.ts +73 -0
- package/dist/core/type-generator.js +215 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +26 -21
- package/dist/types/index.d.ts +31 -6
- package/dist/utils/comment.d.ts +4 -1
- package/dist/utils/comment.js +6 -2
- package/dist/utils/file.d.ts +10 -3
- package/dist/utils/file.js +49 -19
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +1 -0
- package/dist/utils/logger.d.ts +115 -0
- package/dist/utils/logger.js +261 -0
- package/dist/utils/naming.js +3 -2
- package/dist/utils/schema.d.ts +79 -0
- package/dist/utils/schema.js +536 -0
- package/dist/utils/type.d.ts +7 -25
- package/dist/utils/type.js +29 -241
- package/package.json +21 -19
package/dist/utils/type.js
CHANGED
|
@@ -1,240 +1,28 @@
|
|
|
1
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 __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);
|
|
15
|
+
};
|
|
2
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.stripNullFromUnion = stripNullFromUnion;
|
|
4
|
-
exports.swaggerTypeToTsType = swaggerTypeToTsType;
|
|
5
|
-
exports.getRefName = getRefName;
|
|
6
17
|
exports.swaggerParameterToSchema = swaggerParameterToSchema;
|
|
7
18
|
exports.getResponseType = getResponseType;
|
|
8
19
|
exports.getSchemaFromContent = getSchemaFromContent;
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
* 移除联合类型中的顶层 null 类型
|
|
12
|
-
* @param typeStr 类型字符串
|
|
13
|
-
* @returns 移除 null 后的类型字符串
|
|
14
|
-
*/
|
|
15
|
-
function stripNullFromUnion(typeStr) {
|
|
16
|
-
if (!typeStr)
|
|
17
|
-
return 'any';
|
|
18
|
-
const parts = [];
|
|
19
|
-
let current = '';
|
|
20
|
-
let parenDepth = 0;
|
|
21
|
-
let angleDepth = 0;
|
|
22
|
-
let braceDepth = 0;
|
|
23
|
-
let bracketDepth = 0;
|
|
24
|
-
for (let i = 0; i < typeStr.length; i++) {
|
|
25
|
-
const ch = typeStr[i];
|
|
26
|
-
if (ch === '(')
|
|
27
|
-
parenDepth++;
|
|
28
|
-
else if (ch === ')')
|
|
29
|
-
parenDepth = Math.max(0, parenDepth - 1);
|
|
30
|
-
else if (ch === '<')
|
|
31
|
-
angleDepth++;
|
|
32
|
-
else if (ch === '>')
|
|
33
|
-
angleDepth = Math.max(0, angleDepth - 1);
|
|
34
|
-
else if (ch === '{')
|
|
35
|
-
braceDepth++;
|
|
36
|
-
else if (ch === '}')
|
|
37
|
-
braceDepth = Math.max(0, braceDepth - 1);
|
|
38
|
-
else if (ch === '[')
|
|
39
|
-
bracketDepth++;
|
|
40
|
-
else if (ch === ']')
|
|
41
|
-
bracketDepth = Math.max(0, bracketDepth - 1);
|
|
42
|
-
const isTopLevel = parenDepth === 0 &&
|
|
43
|
-
angleDepth === 0 &&
|
|
44
|
-
braceDepth === 0 &&
|
|
45
|
-
bracketDepth === 0;
|
|
46
|
-
if (ch === '|' && isTopLevel) {
|
|
47
|
-
parts.push(current.trim());
|
|
48
|
-
current = '';
|
|
49
|
-
continue;
|
|
50
|
-
}
|
|
51
|
-
current += ch;
|
|
52
|
-
}
|
|
53
|
-
if (current.trim())
|
|
54
|
-
parts.push(current.trim());
|
|
55
|
-
const normalized = Array.from(new Set(parts.filter((part) => part && part !== 'null')));
|
|
56
|
-
return normalized.length > 0 ? normalized.join(' | ') : 'any';
|
|
57
|
-
}
|
|
58
|
-
/**
|
|
59
|
-
* 将 OpenAPI schema 转换为 TypeScript 类型
|
|
60
|
-
* @param schema OpenAPI schema
|
|
61
|
-
* @param schemas 可选的 schemas 上下文,用于查找被引用的类型定义
|
|
62
|
-
* @returns TypeScript类型字符串
|
|
63
|
-
*/
|
|
64
|
-
function swaggerTypeToTsType(schema, schemas) {
|
|
65
|
-
if (!schema)
|
|
66
|
-
return 'any';
|
|
67
|
-
let baseType = 'any';
|
|
68
|
-
if (Array.isArray(schema.type)) {
|
|
69
|
-
const types = schema.type.map((type) => swaggerTypeToTsType({ ...schema, type, nullable: false }, schemas));
|
|
70
|
-
const uniqueTypes = Array.from(new Set(types));
|
|
71
|
-
baseType = uniqueTypes.includes('any') ? 'any' : uniqueTypes.join(' | ');
|
|
72
|
-
}
|
|
73
|
-
else if (schema.enum) {
|
|
74
|
-
baseType = schema.enum
|
|
75
|
-
.map((value) => toLiteralType(value))
|
|
76
|
-
.join(' | ');
|
|
77
|
-
}
|
|
78
|
-
else if (schema.allOf) {
|
|
79
|
-
const refSchema = schema.allOf.find((item) => item.$ref);
|
|
80
|
-
const secondSchema = schema.allOf.find((item) => !item.$ref);
|
|
81
|
-
if (refSchema && secondSchema) {
|
|
82
|
-
const refName = getRefName(refSchema.$ref || '');
|
|
83
|
-
const sanitizedRefName = (0, naming_1.sanitizeTypeName)(refName || '');
|
|
84
|
-
if (secondSchema.properties) {
|
|
85
|
-
const propertyTypes = [];
|
|
86
|
-
for (const propSchema of Object.values(secondSchema.properties)) {
|
|
87
|
-
const propType = swaggerTypeToTsType(propSchema, schemas);
|
|
88
|
-
propertyTypes.push(propType);
|
|
89
|
-
}
|
|
90
|
-
if (propertyTypes.length === 1) {
|
|
91
|
-
baseType = `${sanitizedRefName}<${propertyTypes[0]}>`;
|
|
92
|
-
}
|
|
93
|
-
else if (propertyTypes.length > 1) {
|
|
94
|
-
const combinedType = `{ ${Object.entries(secondSchema.properties)
|
|
95
|
-
.map(([key, value]) => {
|
|
96
|
-
const optional = secondSchema.required?.includes(key) ? '' : '?';
|
|
97
|
-
let type = swaggerTypeToTsType(value, schemas);
|
|
98
|
-
if (optional === '?')
|
|
99
|
-
type = stripNullFromUnion(type);
|
|
100
|
-
return `${key}${optional}: ${type}`;
|
|
101
|
-
})
|
|
102
|
-
.join('; ')} }`;
|
|
103
|
-
baseType = `${sanitizedRefName}<${combinedType}>`;
|
|
104
|
-
}
|
|
105
|
-
else {
|
|
106
|
-
baseType = sanitizedRefName || 'any';
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
else {
|
|
110
|
-
baseType = sanitizedRefName || 'any';
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
else {
|
|
114
|
-
const types = schema.allOf
|
|
115
|
-
.map((item) => swaggerTypeToTsType(item))
|
|
116
|
-
.filter((type) => type !== 'any');
|
|
117
|
-
baseType = types.length > 0 ? types[0] : 'any';
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
else if (schema.anyOf || schema.oneOf) {
|
|
121
|
-
const types = (schema.anyOf || schema.oneOf).map((item) => {
|
|
122
|
-
if (item.type === 'null')
|
|
123
|
-
return 'null';
|
|
124
|
-
return swaggerTypeToTsType(item, schemas);
|
|
125
|
-
});
|
|
126
|
-
if (types.includes('any')) {
|
|
127
|
-
baseType = 'any';
|
|
128
|
-
}
|
|
129
|
-
else {
|
|
130
|
-
const uniqueTypes = Array.from(new Set(types));
|
|
131
|
-
baseType = uniqueTypes.length > 0 ? uniqueTypes.join(' | ') : 'any';
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
else if (schema.$ref) {
|
|
135
|
-
const refName = getRefName(schema.$ref);
|
|
136
|
-
baseType = (0, naming_1.sanitizeTypeName)(refName || 'any');
|
|
137
|
-
if (schemas && refName) {
|
|
138
|
-
const referencedSchema = schemas[refName];
|
|
139
|
-
if (referencedSchema && referencedSchema.type === 'array') {
|
|
140
|
-
baseType = `${baseType}[]`;
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
else if (schema.type === 'array') {
|
|
145
|
-
const itemSchema = schema.items;
|
|
146
|
-
const itemType = swaggerTypeToTsType(itemSchema, schemas);
|
|
147
|
-
if (itemSchema?.$ref && schemas) {
|
|
148
|
-
const refName = getRefName(itemSchema.$ref);
|
|
149
|
-
const referencedSchema = refName ? schemas[refName] : undefined;
|
|
150
|
-
baseType =
|
|
151
|
-
referencedSchema?.type === 'array' ? itemType : `${itemType}[]`;
|
|
152
|
-
}
|
|
153
|
-
else {
|
|
154
|
-
baseType = `${itemType}[]`;
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
else if (schema.type === 'object') {
|
|
158
|
-
if (schema.properties) {
|
|
159
|
-
const properties = Object.entries(schema.properties)
|
|
160
|
-
.map(([key, value]) => {
|
|
161
|
-
const optional = schema.required?.includes(key) ? '' : '?';
|
|
162
|
-
let type = swaggerTypeToTsType(value, schemas);
|
|
163
|
-
if (optional === '?')
|
|
164
|
-
type = stripNullFromUnion(type);
|
|
165
|
-
return ` ${key}${optional}: ${type};`;
|
|
166
|
-
})
|
|
167
|
-
.join('\n');
|
|
168
|
-
baseType = `{\n${properties}\n}`;
|
|
169
|
-
}
|
|
170
|
-
else if (schema.additionalProperties &&
|
|
171
|
-
typeof schema.additionalProperties === 'object') {
|
|
172
|
-
const valueType = swaggerTypeToTsType(schema.additionalProperties, schemas);
|
|
173
|
-
baseType = `Record<string, ${valueType}>`;
|
|
174
|
-
}
|
|
175
|
-
else if (schema.additionalProperties === false) {
|
|
176
|
-
baseType = 'Record<string, never>';
|
|
177
|
-
}
|
|
178
|
-
else {
|
|
179
|
-
baseType = 'Record<string, any>';
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
else {
|
|
183
|
-
switch (schema.type) {
|
|
184
|
-
case 'integer':
|
|
185
|
-
case 'number':
|
|
186
|
-
baseType = 'number';
|
|
187
|
-
break;
|
|
188
|
-
case 'string':
|
|
189
|
-
baseType = 'string';
|
|
190
|
-
break;
|
|
191
|
-
case 'boolean':
|
|
192
|
-
baseType = 'boolean';
|
|
193
|
-
break;
|
|
194
|
-
case 'file':
|
|
195
|
-
baseType = 'File';
|
|
196
|
-
break;
|
|
197
|
-
case 'null':
|
|
198
|
-
baseType = 'null';
|
|
199
|
-
break;
|
|
200
|
-
default:
|
|
201
|
-
baseType = 'any';
|
|
202
|
-
break;
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
if (schema.nullable === true) {
|
|
206
|
-
if (baseType === 'any')
|
|
207
|
-
return 'any';
|
|
208
|
-
if (baseType.includes('null'))
|
|
209
|
-
return baseType;
|
|
210
|
-
return `${baseType} | null`;
|
|
211
|
-
}
|
|
212
|
-
return baseType;
|
|
213
|
-
}
|
|
214
|
-
/**
|
|
215
|
-
* 从 $ref 字符串中提取引用名称
|
|
216
|
-
* @param ref OpenAPI $ref 字符串
|
|
217
|
-
* @returns 引用名称
|
|
218
|
-
*/
|
|
219
|
-
function getRefName(ref) {
|
|
220
|
-
return ref.split('/').pop() || '';
|
|
221
|
-
}
|
|
222
|
-
/**
|
|
223
|
-
* 将枚举值转换为 TypeScript 字面量类型
|
|
224
|
-
* @param value 枚举值
|
|
225
|
-
* @returns 字面量类型字符串
|
|
226
|
-
*/
|
|
227
|
-
function toLiteralType(value) {
|
|
228
|
-
if (value === null)
|
|
229
|
-
return 'null';
|
|
230
|
-
if (typeof value === 'string')
|
|
231
|
-
return `'${value}'`;
|
|
232
|
-
return String(value);
|
|
233
|
-
}
|
|
20
|
+
const schema_1 = require("./schema");
|
|
21
|
+
__exportStar(require("./schema"), exports);
|
|
234
22
|
/**
|
|
235
|
-
* 将 OpenAPI 参数转换为
|
|
23
|
+
* 将 OpenAPI 参数转换为 Schema 对象
|
|
236
24
|
* @param parameter OpenAPI 参数
|
|
237
|
-
* @returns 参数对应的
|
|
25
|
+
* @returns 参数对应的 Schema
|
|
238
26
|
*/
|
|
239
27
|
function swaggerParameterToSchema(parameter) {
|
|
240
28
|
if (parameter.schema) {
|
|
@@ -251,25 +39,23 @@ function swaggerParameterToSchema(parameter) {
|
|
|
251
39
|
* 获取响应类型
|
|
252
40
|
* @param responses OpenAPI 响应对象
|
|
253
41
|
* @param schemas OpenAPI components.schemas
|
|
254
|
-
* @returns TypeScript类型字符串
|
|
42
|
+
* @returns TypeScript 类型字符串
|
|
255
43
|
*/
|
|
256
|
-
function getResponseType(responses, schemas) {
|
|
257
|
-
if (!responses)
|
|
44
|
+
function getResponseType(responses, schemas = {}) {
|
|
45
|
+
if (!responses)
|
|
258
46
|
return 'any';
|
|
259
|
-
}
|
|
260
47
|
const successResponse = getSuccessResponse(responses);
|
|
261
|
-
if (!successResponse)
|
|
48
|
+
if (!successResponse)
|
|
262
49
|
return 'any';
|
|
263
|
-
}
|
|
264
50
|
const contentSchema = getSchemaFromContent(successResponse.content);
|
|
265
51
|
if (contentSchema) {
|
|
266
|
-
return swaggerTypeToTsType(contentSchema, schemas);
|
|
52
|
+
return (0, schema_1.swaggerTypeToTsType)(contentSchema, schemas, 'response');
|
|
267
53
|
}
|
|
268
54
|
return successResponse.description === 'No Content' ? 'void' : 'any';
|
|
269
55
|
}
|
|
270
56
|
/**
|
|
271
57
|
* 从响应集合中获取优先成功响应
|
|
272
|
-
* @param responses OpenAPI响应对象
|
|
58
|
+
* @param responses OpenAPI 响应对象
|
|
273
59
|
* @returns 成功响应对象
|
|
274
60
|
*/
|
|
275
61
|
function getSuccessResponse(responses) {
|
|
@@ -280,12 +66,14 @@ function getSuccessResponse(responses) {
|
|
|
280
66
|
const successStatus = Object.keys(responses)
|
|
281
67
|
.filter((status) => /^2\d\d$/.test(status))
|
|
282
68
|
.sort()[0];
|
|
283
|
-
return successStatus
|
|
69
|
+
return successStatus
|
|
70
|
+
? responses[successStatus]
|
|
71
|
+
: responses.default;
|
|
284
72
|
}
|
|
285
73
|
/**
|
|
286
|
-
* 从 OpenAPI content 对象中获取最合适的
|
|
74
|
+
* 从 OpenAPI content 对象中获取最合适的 Schema
|
|
287
75
|
* @param content OpenAPI content 对象
|
|
288
|
-
* @returns 匹配到的
|
|
76
|
+
* @returns 匹配到的 Schema
|
|
289
77
|
*/
|
|
290
78
|
function getSchemaFromContent(content) {
|
|
291
79
|
if (!content)
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "swagger2api-v3",
|
|
3
|
-
"version": "1.1.
|
|
4
|
-
"description": "A command-line tool for generating TypeScript API interfaces from OpenAPI 3.
|
|
3
|
+
"version": "1.1.11",
|
|
4
|
+
"description": "A command-line tool for generating TypeScript API interfaces from OpenAPI 3.0 documentation",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"type": "commonjs",
|
|
@@ -18,20 +18,21 @@
|
|
|
18
18
|
"test:watch": "jest --watch",
|
|
19
19
|
"test:coverage": "jest --coverage",
|
|
20
20
|
"test:ci": "jest --ci --coverage --watchAll=false",
|
|
21
|
-
"
|
|
21
|
+
"changelog": "conventional-changelog -p angular -i CHANGELOG.md -s -r 0",
|
|
22
|
+
"build": "tsc && pnpm run copy:schema",
|
|
22
23
|
"copy:schema": "node build/copy-schema.js",
|
|
23
24
|
"clean": "rimraf dist",
|
|
24
|
-
"prebuild": "
|
|
25
|
+
"prebuild": "pnpm run clean",
|
|
25
26
|
"start": "node dist/cli/index.js",
|
|
26
|
-
"dev": "
|
|
27
|
+
"dev": "pnpm run build && pnpm start",
|
|
27
28
|
"lint": "prettier --write .",
|
|
28
|
-
"generate": "
|
|
29
|
-
"init": "
|
|
30
|
-
"validate": "
|
|
31
|
-
"swagger:generate": "
|
|
32
|
-
"swagger:run": "
|
|
33
|
-
"swagger:init": "
|
|
34
|
-
"swagger:validate": "
|
|
29
|
+
"generate": "pnpm run build && node dist/cli/index.js generate",
|
|
30
|
+
"init": "pnpm run build && node dist/cli/index.js init",
|
|
31
|
+
"validate": "pnpm run build && node dist/cli/index.js validate",
|
|
32
|
+
"swagger:generate": "pnpm run generate",
|
|
33
|
+
"swagger:run": "pnpm run generate",
|
|
34
|
+
"swagger:init": "pnpm run init",
|
|
35
|
+
"swagger:validate": "pnpm run validate"
|
|
35
36
|
},
|
|
36
37
|
"keywords": [
|
|
37
38
|
"swagger",
|
|
@@ -47,7 +48,7 @@
|
|
|
47
48
|
"homepage": "https://github.com/xiaoyang33/swagger2api-v3#readme",
|
|
48
49
|
"repository": {
|
|
49
50
|
"type": "git",
|
|
50
|
-
"url": "https://github.com/xiaoyang33/swagger2api-v3.git"
|
|
51
|
+
"url": "git+https://github.com/xiaoyang33/swagger2api-v3.git"
|
|
51
52
|
},
|
|
52
53
|
"bugs": {
|
|
53
54
|
"url": "https://github.com/xiaoyang33/swagger2api-v3/issues"
|
|
@@ -55,15 +56,16 @@
|
|
|
55
56
|
"packageManager": "pnpm@10.11.0",
|
|
56
57
|
"devDependencies": {
|
|
57
58
|
"@types/jest": "^30.0.0",
|
|
58
|
-
"@types/node": "^24.
|
|
59
|
+
"@types/node": "^24.13.2",
|
|
60
|
+
"conventional-changelog-cli": "^5.0.0",
|
|
59
61
|
"jest": "^30.4.2",
|
|
60
|
-
"prettier": "^3.
|
|
61
|
-
"rimraf": "^6.
|
|
62
|
+
"prettier": "^3.8.4",
|
|
63
|
+
"rimraf": "^6.1.3",
|
|
62
64
|
"ts-jest": "^29.4.11",
|
|
63
|
-
"typescript": "^
|
|
65
|
+
"typescript": "^6.0.3"
|
|
64
66
|
},
|
|
65
67
|
"dependencies": {
|
|
66
|
-
"
|
|
67
|
-
"commander": "^12.
|
|
68
|
+
"@apidevtools/swagger-parser": "^12.1.0",
|
|
69
|
+
"commander": "^12.1.0"
|
|
68
70
|
}
|
|
69
71
|
}
|