@acrool/rtk-query-codegen-openapi 1.3.0 → 1.4.0-alpha.0
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/lib/bin/cli.mjs +41 -39
- package/lib/bin/cli.mjs.map +1 -1
- package/lib/index.js +297 -35
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +297 -35
- package/lib/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/generators/component-schema-generator.ts +10 -1
- package/src/generators/types-generator.ts +121 -32
- package/src/services/unified-code-generator.ts +100 -14
- package/src/utils/schema-ref-analyzer.ts +218 -0
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import type { OpenAPIV3 } from 'openapi-types';
|
|
2
|
+
import type { OperationDefinition } from '../types';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Schema 引用分析結果
|
|
6
|
+
*/
|
|
7
|
+
export interface SchemaRefAnalysis {
|
|
8
|
+
/** 被多個 group 共用的 schema 名稱 */
|
|
9
|
+
sharedSchemas: Set<string>;
|
|
10
|
+
/** 每個 group 專屬的 schema 名稱 */
|
|
11
|
+
groupLocalSchemas: Map<string, Set<string>>;
|
|
12
|
+
/** 完全未被引用的 schema 名稱 */
|
|
13
|
+
unusedSchemas: Set<string>;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* 從 OpenAPI schema 物件中遞迴收集所有 $ref 引用的 schema 名稱
|
|
18
|
+
*/
|
|
19
|
+
function collectRefsFromSchema(schema: any, refs: Set<string>): void {
|
|
20
|
+
if (!schema || typeof schema !== 'object') return;
|
|
21
|
+
|
|
22
|
+
if (schema.$ref && typeof schema.$ref === 'string') {
|
|
23
|
+
const match = schema.$ref.match(/^#\/components\/schemas\/(.+)$/);
|
|
24
|
+
if (match) {
|
|
25
|
+
refs.add(match[1]);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// 遍歷所有屬性
|
|
30
|
+
if (schema.properties) {
|
|
31
|
+
for (const prop of Object.values(schema.properties)) {
|
|
32
|
+
collectRefsFromSchema(prop, refs);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// array items
|
|
37
|
+
if (schema.items) {
|
|
38
|
+
collectRefsFromSchema(schema.items, refs);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// additionalProperties
|
|
42
|
+
if (schema.additionalProperties && typeof schema.additionalProperties === 'object') {
|
|
43
|
+
collectRefsFromSchema(schema.additionalProperties, refs);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// allOf / oneOf / anyOf
|
|
47
|
+
for (const key of ['allOf', 'oneOf', 'anyOf'] as const) {
|
|
48
|
+
if (Array.isArray(schema[key])) {
|
|
49
|
+
for (const item of schema[key]) {
|
|
50
|
+
collectRefsFromSchema(item, refs);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* 從一組 operation definitions 收集所有直接引用的 schema 名稱
|
|
58
|
+
*/
|
|
59
|
+
function collectDirectRefs(operationDefs: OperationDefinition[]): Set<string> {
|
|
60
|
+
const refs = new Set<string>();
|
|
61
|
+
|
|
62
|
+
for (const opDef of operationDefs) {
|
|
63
|
+
const op = opDef.operation;
|
|
64
|
+
|
|
65
|
+
// 收集 parameters 中的 refs
|
|
66
|
+
if (op.parameters) {
|
|
67
|
+
for (const param of op.parameters) {
|
|
68
|
+
const p = param as OpenAPIV3.ParameterObject;
|
|
69
|
+
if (p.schema) {
|
|
70
|
+
collectRefsFromSchema(p.schema, refs);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// 收集 requestBody 中的 refs
|
|
76
|
+
if (op.requestBody) {
|
|
77
|
+
const rb = op.requestBody as OpenAPIV3.RequestBodyObject;
|
|
78
|
+
if (rb.content) {
|
|
79
|
+
for (const ct of Object.values(rb.content)) {
|
|
80
|
+
if (ct.schema) {
|
|
81
|
+
collectRefsFromSchema(ct.schema, refs);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// 收集 responses 中的 refs
|
|
88
|
+
if (op.responses) {
|
|
89
|
+
for (const resp of Object.values(op.responses)) {
|
|
90
|
+
const r = resp as OpenAPIV3.ResponseObject;
|
|
91
|
+
if (r.content) {
|
|
92
|
+
for (const ct of Object.values(r.content)) {
|
|
93
|
+
if (ct.schema) {
|
|
94
|
+
collectRefsFromSchema(ct.schema, refs);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return refs;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* 解析 schema 的遞迴依賴(transitive dependencies)
|
|
107
|
+
* 例如 TaskResponseDto 引用了 TaskDto,TaskDto 又引用了 TaskStatusRefDto
|
|
108
|
+
*/
|
|
109
|
+
function resolveTransitiveDeps(
|
|
110
|
+
directRefs: Set<string>,
|
|
111
|
+
allSchemas: Record<string, any>
|
|
112
|
+
): Set<string> {
|
|
113
|
+
const resolved = new Set<string>();
|
|
114
|
+
const queue = [...directRefs];
|
|
115
|
+
|
|
116
|
+
while (queue.length > 0) {
|
|
117
|
+
const name = queue.pop()!;
|
|
118
|
+
if (resolved.has(name)) continue;
|
|
119
|
+
resolved.add(name);
|
|
120
|
+
|
|
121
|
+
const schema = allSchemas[name];
|
|
122
|
+
if (!schema) continue;
|
|
123
|
+
|
|
124
|
+
const nestedRefs = new Set<string>();
|
|
125
|
+
collectRefsFromSchema(schema, nestedRefs);
|
|
126
|
+
|
|
127
|
+
for (const ref of nestedRefs) {
|
|
128
|
+
if (!resolved.has(ref)) {
|
|
129
|
+
queue.push(ref);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return resolved;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* 分析所有 group 的 schema 引用,分類為 shared / group-local / unused
|
|
139
|
+
*/
|
|
140
|
+
export function analyzeSchemaRefs(
|
|
141
|
+
groupOperations: Map<string, OperationDefinition[]>,
|
|
142
|
+
allSchemas: Record<string, any>,
|
|
143
|
+
allSchemaNames: string[]
|
|
144
|
+
): SchemaRefAnalysis {
|
|
145
|
+
// 步驟 1:收集每個 group 的完整引用(含遞迴依賴)
|
|
146
|
+
const groupRefs = new Map<string, Set<string>>();
|
|
147
|
+
|
|
148
|
+
for (const [groupKey, opDefs] of groupOperations) {
|
|
149
|
+
const directRefs = collectDirectRefs(opDefs);
|
|
150
|
+
const fullRefs = resolveTransitiveDeps(directRefs, allSchemas);
|
|
151
|
+
groupRefs.set(groupKey, fullRefs);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// 步驟 2:統計每個 schema 被多少個 group 引用
|
|
155
|
+
const refCountMap = new Map<string, Set<string>>();
|
|
156
|
+
|
|
157
|
+
for (const [groupKey, refs] of groupRefs) {
|
|
158
|
+
for (const schemaName of refs) {
|
|
159
|
+
if (!refCountMap.has(schemaName)) {
|
|
160
|
+
refCountMap.set(schemaName, new Set());
|
|
161
|
+
}
|
|
162
|
+
refCountMap.get(schemaName)!.add(groupKey);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// 步驟 3:分類
|
|
167
|
+
const sharedSchemas = new Set<string>();
|
|
168
|
+
const groupLocalSchemas = new Map<string, Set<string>>();
|
|
169
|
+
const unusedSchemas = new Set<string>();
|
|
170
|
+
|
|
171
|
+
for (const schemaName of allSchemaNames) {
|
|
172
|
+
const groups = refCountMap.get(schemaName);
|
|
173
|
+
|
|
174
|
+
if (!groups || groups.size === 0) {
|
|
175
|
+
unusedSchemas.add(schemaName);
|
|
176
|
+
} else if (groups.size === 1) {
|
|
177
|
+
const groupKey = [...groups][0];
|
|
178
|
+
if (!groupLocalSchemas.has(groupKey)) {
|
|
179
|
+
groupLocalSchemas.set(groupKey, new Set());
|
|
180
|
+
}
|
|
181
|
+
groupLocalSchemas.get(groupKey)!.add(schemaName);
|
|
182
|
+
} else {
|
|
183
|
+
sharedSchemas.add(schemaName);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// 步驟 4:確保 group-local schema 的依賴一致性
|
|
188
|
+
// 如果 group-A-local 的 schema 依賴了 group-B-local 的 schema,兩者都提升為 shared
|
|
189
|
+
let changed = true;
|
|
190
|
+
while (changed) {
|
|
191
|
+
changed = false;
|
|
192
|
+
for (const [groupKey, localSchemas] of groupLocalSchemas) {
|
|
193
|
+
for (const schemaName of [...localSchemas]) {
|
|
194
|
+
const schema = allSchemas[schemaName];
|
|
195
|
+
if (!schema) continue;
|
|
196
|
+
|
|
197
|
+
const deps = new Set<string>();
|
|
198
|
+
collectRefsFromSchema(schema, deps);
|
|
199
|
+
|
|
200
|
+
for (const dep of deps) {
|
|
201
|
+
// 檢查 dep 是否是其他 group 的 local schema
|
|
202
|
+
for (const [otherGroup, otherLocals] of groupLocalSchemas) {
|
|
203
|
+
if (otherGroup !== groupKey && otherLocals.has(dep)) {
|
|
204
|
+
// 衝突!兩者都提升為 shared
|
|
205
|
+
sharedSchemas.add(dep);
|
|
206
|
+
sharedSchemas.add(schemaName);
|
|
207
|
+
otherLocals.delete(dep);
|
|
208
|
+
localSchemas.delete(schemaName);
|
|
209
|
+
changed = true;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
return { sharedSchemas, groupLocalSchemas, unusedSchemas };
|
|
218
|
+
}
|