czh-api 1.0.3 → 1.0.5
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/CHANGELOG.md +30 -5
- package/README.md +4 -11
- package/dist/commands/build.js +320 -107
- package/dist/core/parser.js +134 -16
- package/dist/templates/api.hbs +1 -6
- package/package.json +1 -1
- package/src/commands/build.ts +427 -159
- package/src/core/parser.ts +170 -34
- package/src/templates/api.hbs +1 -6
package/dist/core/parser.js
CHANGED
|
@@ -87,11 +87,68 @@ function convertOpenApiTypeToTypeScript(openApiType) {
|
|
|
87
87
|
case 'number':
|
|
88
88
|
return 'number';
|
|
89
89
|
default:
|
|
90
|
-
return
|
|
90
|
+
return openApiType;
|
|
91
91
|
}
|
|
92
92
|
}
|
|
93
|
+
function resolveSchemaToTypeScript(schema, allSchemas) {
|
|
94
|
+
if (!schema)
|
|
95
|
+
return 'any';
|
|
96
|
+
if (isReferenceObject(schema)) {
|
|
97
|
+
return getSchemaName(schema.$ref) || 'any';
|
|
98
|
+
}
|
|
99
|
+
if (schema.anyOf && Array.isArray(schema.anyOf) && schema.anyOf.length > 0) {
|
|
100
|
+
const unionTypes = schema.anyOf
|
|
101
|
+
.map(item => resolveSchemaToTypeScript(item, allSchemas))
|
|
102
|
+
.filter(Boolean);
|
|
103
|
+
if (unionTypes.length > 0) {
|
|
104
|
+
return [...new Set(unionTypes)].join(' | ');
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
if (schema.oneOf && Array.isArray(schema.oneOf) && schema.oneOf.length > 0) {
|
|
108
|
+
const unionTypes = schema.oneOf
|
|
109
|
+
.map(item => resolveSchemaToTypeScript(item, allSchemas))
|
|
110
|
+
.filter(Boolean);
|
|
111
|
+
if (unionTypes.length > 0) {
|
|
112
|
+
return [...new Set(unionTypes)].join(' | ');
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
if (schema.allOf && Array.isArray(schema.allOf) && schema.allOf.length > 0) {
|
|
116
|
+
const intersectionTypes = schema.allOf
|
|
117
|
+
.map(item => resolveSchemaToTypeScript(item, allSchemas))
|
|
118
|
+
.filter(Boolean);
|
|
119
|
+
if (intersectionTypes.length > 0) {
|
|
120
|
+
return [...new Set(intersectionTypes)].join(' & ');
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
if (schema.type === 'array') {
|
|
124
|
+
const itemType = resolveSchemaToTypeScript(schema.items, allSchemas);
|
|
125
|
+
return `${itemType || 'any'}[]`;
|
|
126
|
+
}
|
|
127
|
+
if (schema.type === 'object') {
|
|
128
|
+
if (schema.properties && Object.keys(schema.properties).length > 0) {
|
|
129
|
+
const requiredSet = new Set(schema.required || []);
|
|
130
|
+
const inlineFields = Object.entries(schema.properties).map(([key, value]) => {
|
|
131
|
+
const fieldType = resolveSchemaToTypeScript(value, allSchemas);
|
|
132
|
+
const optional = requiredSet.has(key) ? '' : '?';
|
|
133
|
+
return `${key}${optional}: ${fieldType || 'any'}`;
|
|
134
|
+
});
|
|
135
|
+
return `{ ${inlineFields.join('; ')} }`;
|
|
136
|
+
}
|
|
137
|
+
if (schema.additionalProperties) {
|
|
138
|
+
if (schema.additionalProperties === true) {
|
|
139
|
+
return 'Record<string, any>';
|
|
140
|
+
}
|
|
141
|
+
const valueType = resolveSchemaToTypeScript(schema.additionalProperties, allSchemas);
|
|
142
|
+
return `Record<string, ${valueType || 'any'}>`;
|
|
143
|
+
}
|
|
144
|
+
return 'any';
|
|
145
|
+
}
|
|
146
|
+
const baseType = convertOpenApiTypeToTypeScript(schema.type);
|
|
147
|
+
const nullable = schema.nullable ? ' | null' : '';
|
|
148
|
+
return `${baseType}${nullable}`;
|
|
149
|
+
}
|
|
93
150
|
function extractJsdocParamsFromSchema(schema, allSchemas) {
|
|
94
|
-
var _a;
|
|
151
|
+
var _a, _b;
|
|
95
152
|
const params = [];
|
|
96
153
|
if (!schema)
|
|
97
154
|
return params;
|
|
@@ -106,9 +163,12 @@ function extractJsdocParamsFromSchema(schema, allSchemas) {
|
|
|
106
163
|
if (targetSchema === null || targetSchema === void 0 ? void 0 : targetSchema.properties) {
|
|
107
164
|
for (const propName in targetSchema.properties) {
|
|
108
165
|
const prop = targetSchema.properties[propName];
|
|
109
|
-
let propType =
|
|
166
|
+
let propType = resolveSchemaToTypeScript(prop, allSchemas);
|
|
167
|
+
const propDescription = isReferenceObject(prop)
|
|
168
|
+
? (((_a = allSchemas[getSchemaName(prop.$ref)]) === null || _a === void 0 ? void 0 : _a.description) || '')
|
|
169
|
+
: ((prop === null || prop === void 0 ? void 0 : prop.description) || '');
|
|
110
170
|
// 处理 anyOf 数组 (FastAPI 常用的联合类型)
|
|
111
|
-
if (prop.anyOf && Array.isArray(prop.anyOf)) {
|
|
171
|
+
if (false && prop.anyOf && Array.isArray(prop.anyOf)) {
|
|
112
172
|
const types = prop.anyOf.map(item => {
|
|
113
173
|
if (isReferenceObject(item)) {
|
|
114
174
|
return getSchemaName(item.$ref);
|
|
@@ -130,7 +190,7 @@ function extractJsdocParamsFromSchema(schema, allSchemas) {
|
|
|
130
190
|
}
|
|
131
191
|
}
|
|
132
192
|
// 处理 oneOf 数组
|
|
133
|
-
else if (prop.oneOf && Array.isArray(prop.oneOf)) {
|
|
193
|
+
else if (false && prop.oneOf && Array.isArray(prop.oneOf)) {
|
|
134
194
|
const types = prop.oneOf.map(item => {
|
|
135
195
|
if (isReferenceObject(item)) {
|
|
136
196
|
return getSchemaName(item.$ref);
|
|
@@ -152,14 +212,26 @@ function extractJsdocParamsFromSchema(schema, allSchemas) {
|
|
|
152
212
|
}
|
|
153
213
|
}
|
|
154
214
|
// 处理普通类型
|
|
155
|
-
else if (prop.type) {
|
|
156
|
-
|
|
215
|
+
else if (false && prop.type) {
|
|
216
|
+
const propSchema = prop;
|
|
217
|
+
if (propSchema.type === 'array' && propSchema.items) {
|
|
218
|
+
if (isReferenceObject(propSchema.items)) {
|
|
219
|
+
propType = `${getSchemaName(propSchema.items.$ref)}[]`;
|
|
220
|
+
}
|
|
221
|
+
else {
|
|
222
|
+
const itemType = convertOpenApiTypeToTypeScript(propSchema.items.type);
|
|
223
|
+
propType = `${itemType}[]`;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
else {
|
|
227
|
+
propType = convertOpenApiTypeToTypeScript(propSchema.type);
|
|
228
|
+
}
|
|
157
229
|
}
|
|
158
230
|
params.push({
|
|
159
231
|
name: propName,
|
|
160
|
-
type: propType,
|
|
161
|
-
description:
|
|
162
|
-
required: (
|
|
232
|
+
type: propType || 'any',
|
|
233
|
+
description: propDescription,
|
|
234
|
+
required: (_b = targetSchema.required) === null || _b === void 0 ? void 0 : _b.includes(propName)
|
|
163
235
|
});
|
|
164
236
|
}
|
|
165
237
|
}
|
|
@@ -238,6 +310,9 @@ const processApi = (api, excludePaths = [], includePaths = [], pathPrefixes = []
|
|
|
238
310
|
let requestBodyTypeName = undefined;
|
|
239
311
|
let contentType = undefined;
|
|
240
312
|
const jsdocParams = [];
|
|
313
|
+
const paramsJsdocParams = [];
|
|
314
|
+
const dataJsdocParams = [];
|
|
315
|
+
const responseJsdocParams = [];
|
|
241
316
|
// --- FormData Detection ---
|
|
242
317
|
let isFormData = false;
|
|
243
318
|
// Method 1: Check requestBody
|
|
@@ -331,13 +406,17 @@ const processApi = (api, excludePaths = [], includePaths = [], pathPrefixes = []
|
|
|
331
406
|
requestBodyTypeName = typeName;
|
|
332
407
|
modules[moduleName].schemas[typeName] = formDataSchema;
|
|
333
408
|
referencedTypes.push(typeName);
|
|
334
|
-
|
|
409
|
+
const formDataJsdoc = extractJsdocParamsFromSchema(formDataSchema, allSchemas);
|
|
410
|
+
jsdocParams.push(...formDataJsdoc);
|
|
411
|
+
dataJsdocParams.push(...formDataJsdoc);
|
|
335
412
|
}
|
|
336
413
|
if (Object.keys(paramsSchema.properties || {}).length > 0) {
|
|
337
414
|
requestParamsTypeName = `${functionName.charAt(0).toUpperCase() + functionName.slice(1)}Params`;
|
|
338
415
|
modules[moduleName].schemas[requestParamsTypeName] = paramsSchema;
|
|
339
416
|
referencedTypes.push(requestParamsTypeName);
|
|
340
|
-
|
|
417
|
+
const paramsJsdoc = extractJsdocParamsFromSchema(paramsSchema, allSchemas);
|
|
418
|
+
jsdocParams.push(...paramsJsdoc);
|
|
419
|
+
paramsJsdocParams.push(...paramsJsdoc);
|
|
341
420
|
}
|
|
342
421
|
}
|
|
343
422
|
// Handle standard Request Body
|
|
@@ -350,7 +429,9 @@ const processApi = (api, excludePaths = [], includePaths = [], pathPrefixes = []
|
|
|
350
429
|
requestBodyTypeName = name;
|
|
351
430
|
addSchemaWithDependencies(name, modules[moduleName], allSchemas);
|
|
352
431
|
referencedTypes.push(name);
|
|
353
|
-
|
|
432
|
+
const bodyJsdoc = extractJsdocParamsFromSchema(jsonContent.schema, allSchemas);
|
|
433
|
+
jsdocParams.push(...bodyJsdoc);
|
|
434
|
+
dataJsdocParams.push(...bodyJsdoc);
|
|
354
435
|
}
|
|
355
436
|
else {
|
|
356
437
|
// Handle inline schema (including arrays)
|
|
@@ -367,11 +448,15 @@ const processApi = (api, excludePaths = [], includePaths = [], pathPrefixes = []
|
|
|
367
448
|
addSchemaWithDependencies(itemSchemaName, modules[moduleName], allSchemas);
|
|
368
449
|
}
|
|
369
450
|
else {
|
|
370
|
-
|
|
451
|
+
const arrayJsdoc = extractJsdocParamsFromSchema(schema.items, allSchemas);
|
|
452
|
+
jsdocParams.push(...arrayJsdoc);
|
|
453
|
+
dataJsdocParams.push(...arrayJsdoc);
|
|
371
454
|
}
|
|
372
455
|
}
|
|
373
456
|
else if (schema.type === 'object') {
|
|
374
|
-
|
|
457
|
+
const objJsdoc = extractJsdocParamsFromSchema(schema, allSchemas);
|
|
458
|
+
jsdocParams.push(...objJsdoc);
|
|
459
|
+
dataJsdocParams.push(...objJsdoc);
|
|
375
460
|
}
|
|
376
461
|
}
|
|
377
462
|
}
|
|
@@ -385,7 +470,8 @@ const processApi = (api, excludePaths = [], includePaths = [], pathPrefixes = []
|
|
|
385
470
|
requestBodyTypeName = typeName;
|
|
386
471
|
modules[moduleName].schemas[typeName] = formDataContent.schema;
|
|
387
472
|
referencedTypes.push(typeName);
|
|
388
|
-
|
|
473
|
+
const formJsdoc = extractJsdocParamsFromSchema(formDataContent.schema, allSchemas);
|
|
474
|
+
dataJsdocParams.push(...formJsdoc);
|
|
389
475
|
}
|
|
390
476
|
}
|
|
391
477
|
// Handle Response Body
|
|
@@ -399,6 +485,35 @@ const processApi = (api, excludePaths = [], includePaths = [], pathPrefixes = []
|
|
|
399
485
|
responseTypeName = name;
|
|
400
486
|
addSchemaWithDependencies(name, modules[moduleName], allSchemas);
|
|
401
487
|
referencedTypes.push(name);
|
|
488
|
+
responseJsdocParams.push(...extractJsdocParamsFromSchema(schema, allSchemas));
|
|
489
|
+
}
|
|
490
|
+
else if (schema && !isReferenceObject(schema)) {
|
|
491
|
+
const inlineSchema = schema;
|
|
492
|
+
if (inlineSchema.type === 'object' || inlineSchema.properties) {
|
|
493
|
+
// Generate a named type for inline response schema
|
|
494
|
+
const typeName = `${functionName.charAt(0).toUpperCase() + functionName.slice(1)}Response`;
|
|
495
|
+
responseTypeName = typeName;
|
|
496
|
+
modules[moduleName].schemas[typeName] = inlineSchema;
|
|
497
|
+
referencedTypes.push(typeName);
|
|
498
|
+
responseJsdocParams.push(...extractJsdocParamsFromSchema(inlineSchema, allSchemas));
|
|
499
|
+
}
|
|
500
|
+
else if (inlineSchema.type === 'array' && inlineSchema.items) {
|
|
501
|
+
if (isReferenceObject(inlineSchema.items)) {
|
|
502
|
+
const itemSchemaName = getSchemaName(inlineSchema.items.$ref);
|
|
503
|
+
// Prefer direct `ItemType[]` for array responses to avoid unnecessary alias schema compilation.
|
|
504
|
+
responseTypeName = `${itemSchemaName}[]`;
|
|
505
|
+
referencedTypes.push(itemSchemaName);
|
|
506
|
+
addSchemaWithDependencies(itemSchemaName, modules[moduleName], allSchemas);
|
|
507
|
+
responseJsdocParams.push(...extractJsdocParamsFromSchema(inlineSchema.items, allSchemas));
|
|
508
|
+
}
|
|
509
|
+
else {
|
|
510
|
+
const typeName = `${functionName.charAt(0).toUpperCase() + functionName.slice(1)}Response`;
|
|
511
|
+
responseTypeName = typeName;
|
|
512
|
+
modules[moduleName].schemas[typeName] = inlineSchema;
|
|
513
|
+
referencedTypes.push(typeName);
|
|
514
|
+
responseJsdocParams.push(...extractJsdocParamsFromSchema(inlineSchema, allSchemas));
|
|
515
|
+
}
|
|
516
|
+
}
|
|
402
517
|
}
|
|
403
518
|
}
|
|
404
519
|
// Convert path to template literal string for path parameters
|
|
@@ -416,6 +531,9 @@ const processApi = (api, excludePaths = [], includePaths = [], pathPrefixes = []
|
|
|
416
531
|
hasData: !!requestBodyTypeName,
|
|
417
532
|
contentType,
|
|
418
533
|
jsdocParams,
|
|
534
|
+
paramsJsdocParams,
|
|
535
|
+
dataJsdocParams,
|
|
536
|
+
responseJsdocParams,
|
|
419
537
|
};
|
|
420
538
|
modules[moduleName].endpoints.push(endpoint);
|
|
421
539
|
}
|
package/dist/templates/api.hbs
CHANGED
|
@@ -10,12 +10,7 @@ export const {{functionName}} = ({{#if hasParams}}params: {{requestParamsTypeNam
|
|
|
10
10
|
return http.request<{{responseTypeName}}>({
|
|
11
11
|
url: `{{path}}`,
|
|
12
12
|
method: '{{method}}',
|
|
13
|
-
{{#if hasParams}}
|
|
14
|
-
params,
|
|
15
|
-
{{/if}}
|
|
16
|
-
{{#if hasData}}
|
|
17
|
-
data,
|
|
18
|
-
{{/if}}
|
|
13
|
+
{{#if hasParams}}{{#unless (eq method 'put')}}{{#unless (eq method 'post')}}params,{{/unless}}{{/unless}}{{/if}}{{#if hasData}}data,{{/if}}
|
|
19
14
|
{{#if contentType}}
|
|
20
15
|
headers: { 'Content-Type': '{{contentType}}' },
|
|
21
16
|
{{/if}}
|