czh-api 1.0.1 → 1.0.3

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.
@@ -42,26 +42,91 @@ function addSchemaWithDependencies(name: string, module: Module, allSchemas: { [
42
42
 
43
43
  const schema = allSchemas[name];
44
44
  if (!schema) {
45
+ console.warn(`警告: Schema "${name}" 未找到,跳过此引用`);
45
46
  return; // Schema not found
46
47
  }
47
48
 
48
49
  module.schemas[name] = schema as OpenAPIV3.SchemaObject;
49
50
 
50
- // Recursively add dependencies
51
- JSON.stringify(schema, (key, value) => {
52
- if (key === '$ref' && typeof value === 'string') {
53
- const depName = getSchemaName(value);
54
- addSchemaWithDependencies(depName, module, allSchemas);
55
- }
56
- return value;
57
- });
51
+ // Recursively add dependencies with error handling
52
+ try {
53
+ JSON.stringify(schema, (key, value) => {
54
+ if (key === '$ref' && typeof value === 'string') {
55
+ const depName = getSchemaName(value);
56
+ if (depName && allSchemas[depName]) {
57
+ addSchemaWithDependencies(depName, module, allSchemas);
58
+ } else {
59
+ console.warn(`警告: 依赖 Schema "${depName}" 未找到,跳过此引用`);
60
+ }
61
+ }
62
+ return value;
63
+ });
64
+ } catch (error) {
65
+ console.warn(`警告: 处理 Schema "${name}" 的依赖时出错:`, error);
66
+ }
58
67
  }
59
68
 
60
- function getModuleName(path: string): string {
69
+ function toCamelCase(str: string): string {
70
+ return str
71
+ .split('/')
72
+ .filter(p => p)
73
+ .map((part, index) => {
74
+ const cleaned = part.replace(/[^a-zA-Z0-9]/g, '');
75
+ if (index === 0) {
76
+ return cleaned.charAt(0).toLowerCase() + cleaned.slice(1);
77
+ }
78
+ return cleaned.charAt(0).toUpperCase() + cleaned.slice(1);
79
+ })
80
+ .join('');
81
+ }
82
+
83
+ function getModuleName(path: string, pathPrefixes: Array<{ path: string; packageName?: string }> = []): string {
84
+ // 尝试匹配配置的路径前缀
85
+ for (const prefix of pathPrefixes) {
86
+ if (path.startsWith(prefix.path)) {
87
+ // 获取前缀后的路径部分
88
+ const remainingPath = path.substring(prefix.path.length);
89
+ const parts = remainingPath.split('/').filter(p => p && !p.startsWith('{'));
90
+
91
+ // 确定包名
92
+ const packageName = prefix.packageName || toCamelCase(prefix.path);
93
+
94
+ // 如果有二级路径,使用二级路径作为子模块
95
+ if (parts.length > 0 && parts[0]) {
96
+ return `${packageName}/${parts[0]}`;
97
+ }
98
+
99
+ // 如果没有二级路径,直接使用包名
100
+ return packageName;
101
+ }
102
+ }
103
+
104
+ // 如果没有匹配到配置的前缀,使用默认逻辑
61
105
  const parts = path.split('/').filter(p => p && !p.startsWith('{'));
62
106
  return parts[0] || 'default';
63
107
  }
64
108
 
109
+ function convertOpenApiTypeToTypeScript(openApiType: string | undefined): string {
110
+ if (!openApiType) return 'any';
111
+
112
+ switch (openApiType) {
113
+ case 'integer':
114
+ return 'number';
115
+ case 'object':
116
+ return 'any';
117
+ case 'array':
118
+ return 'any[]';
119
+ case 'boolean':
120
+ return 'boolean';
121
+ case 'string':
122
+ return 'string';
123
+ case 'number':
124
+ return 'number';
125
+ default:
126
+ return 'any';
127
+ }
128
+ }
129
+
65
130
  function extractJsdocParamsFromSchema(schema: OpenAPIV3.SchemaObject | OpenAPIV3.ReferenceObject, allSchemas: { [key: string]: any }): Required<Endpoint>['jsdocParams'] {
66
131
  const params: Required<Endpoint>['jsdocParams'] = [];
67
132
  if (!schema) return params;
@@ -78,12 +143,60 @@ function extractJsdocParamsFromSchema(schema: OpenAPIV3.SchemaObject | OpenAPIV3
78
143
  for (const propName in targetSchema.properties) {
79
144
  const prop = targetSchema.properties[propName] as OpenAPIV3.SchemaObject;
80
145
 
81
- // 调试: 打印出当前处理的属性
82
- // console.log(`正在处理属性: ${propName}`, '值为:', prop);
146
+ let propType = 'any';
147
+
148
+ // 处理 anyOf 数组 (FastAPI 常用的联合类型)
149
+ if (prop.anyOf && Array.isArray(prop.anyOf)) {
150
+ const types = prop.anyOf.map(item => {
151
+ if (isReferenceObject(item)) {
152
+ return getSchemaName(item.$ref);
153
+ } else {
154
+ const itemSchema = item as OpenAPIV3.SchemaObject;
155
+ // 处理 null 类型 (在 OpenAPI 中可能以不同方式表示)
156
+ if ((itemSchema as any).type === 'null' ||
157
+ itemSchema.type === undefined && (itemSchema as any).nullable === true ||
158
+ JSON.stringify(itemSchema) === '{"type":"null"}' ||
159
+ Object.keys(itemSchema).length === 0) {
160
+ return 'null';
161
+ }
162
+ return convertOpenApiTypeToTypeScript(itemSchema.type);
163
+ }
164
+ }).filter(type => type && type !== ''); // 只过滤掉空字符串,保留 any
165
+
166
+ if (types.length > 0) {
167
+ propType = types.join(' | ');
168
+ }
169
+ }
170
+ // 处理 oneOf 数组
171
+ else if (prop.oneOf && Array.isArray(prop.oneOf)) {
172
+ const types = prop.oneOf.map(item => {
173
+ if (isReferenceObject(item)) {
174
+ return getSchemaName(item.$ref);
175
+ } else {
176
+ const itemSchema = item as OpenAPIV3.SchemaObject;
177
+ // 处理 null 类型 (在 OpenAPI 中可能以不同方式表示)
178
+ if ((itemSchema as any).type === 'null' ||
179
+ itemSchema.type === undefined && (itemSchema as any).nullable === true ||
180
+ JSON.stringify(itemSchema) === '{"type":"null"}' ||
181
+ Object.keys(itemSchema).length === 0) {
182
+ return 'null';
183
+ }
184
+ return convertOpenApiTypeToTypeScript(itemSchema.type);
185
+ }
186
+ }).filter(type => type && type !== ''); // 只过滤掉空字符串,保留 any
187
+
188
+ if (types.length > 0) {
189
+ propType = types.join(' | ');
190
+ }
191
+ }
192
+ // 处理普通类型
193
+ else if (prop.type) {
194
+ propType = convertOpenApiTypeToTypeScript(prop.type);
195
+ }
83
196
 
84
197
  params.push({
85
198
  name: propName,
86
- type: prop?.type || 'any',
199
+ type: propType,
87
200
  description: prop?.description || '',
88
201
  required: targetSchema.required?.includes(propName)
89
202
  });
@@ -109,15 +222,23 @@ function getModuleNameFromPackage(operation: OpenAPIV3.OperationObject): string
109
222
  /**
110
223
  * Processes the validated OpenAPI document into a structured format for code generation.
111
224
  * @param api The bundled OpenAPI document.
225
+ * @param excludePaths Paths to exclude (by prefix).
226
+ * @param includePaths Paths to include (by prefix). If provided, only these paths will be processed.
227
+ * @param pathPrefixes Path prefix configurations for custom module grouping.
112
228
  * @returns A structured representation of modules and their endpoints.
113
229
  */
114
- export const processApi = (api: OpenAPI.Document, excludePaths: string[] = []): Modules => {
230
+ export const processApi = (api: OpenAPI.Document, excludePaths: string[] = [], includePaths: string[] = [], pathPrefixes: Array<{ path: string; packageName?: string }> = []): Modules => {
115
231
  const modules: Modules = {};
116
232
  const allSchemas = (api as OpenAPIV3.Document).components?.schemas || (api as any).definitions ||{};
117
233
 
118
234
  const moduleFunctionNames: { [moduleName: string]: Set<string> } = {};
119
235
 
120
236
  for (const path in api.paths) {
237
+ // 如果配置了 includePaths,只处理匹配的路径
238
+ if (includePaths.length > 0 && !includePaths.some(include => path.startsWith(include))) {
239
+ continue;
240
+ }
241
+ // 排除 excludePaths 中的路径
121
242
  if (excludePaths.some(exclude => path.startsWith(exclude))) {
122
243
  continue;
123
244
  }
@@ -134,7 +255,7 @@ export const processApi = (api: OpenAPI.Document, excludePaths: string[] = []):
134
255
  if (!operation.tags) continue;
135
256
 
136
257
  const moduleNameFromPackage = getModuleNameFromPackage(operation);
137
- const moduleName = moduleNameFromPackage || getModuleName(path);
258
+ const moduleName = moduleNameFromPackage || getModuleName(path, pathPrefixes);
138
259
 
139
260
  if (!modules[moduleName]) {
140
261
  modules[moduleName] = {
@@ -220,13 +341,6 @@ export const processApi = (api: OpenAPI.Document, excludePaths: string[] = []):
220
341
 
221
342
  for (const param of operation.parameters) {
222
343
  if (!isReferenceObject(param)) {
223
- const paramToAdd = {
224
- name: param.name,
225
- description: param.description || '',
226
- required: param.required,
227
- type: (param.schema as any)?.type || 'any'
228
- };
229
-
230
344
  // If the parameter's schema is a reference, expand its properties
231
345
  if (param.in === 'query' && param.schema && isReferenceObject(param.schema)) {
232
346
  const schemaName = getSchemaName(param.schema.$ref);