@acrool/rtk-query-codegen-openapi 0.0.2-test.8 → 0.0.2-test.9
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/index.js +158 -24
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +158 -24
- package/lib/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/generate.ts +203 -37
package/src/generate.ts
CHANGED
|
@@ -147,23 +147,24 @@ export async function generateApi(
|
|
|
147
147
|
const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });
|
|
148
148
|
|
|
149
149
|
const allTypeDefinitions: ts.Statement[] = [];
|
|
150
|
+
const definedTypeNames = new Set<string>();
|
|
150
151
|
|
|
151
152
|
const components = v3Doc.components;
|
|
152
153
|
if (components) {
|
|
153
154
|
const componentDefinitions = Object.entries(components).map(([componentType, componentDefs]) => {
|
|
154
|
-
const typeEntries = Object.entries(componentDefs as Record<string, unknown>)
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
155
|
+
const typeEntries = Object.entries(componentDefs as Record<string, unknown>)
|
|
156
|
+
.map(([name, def]) => {
|
|
157
|
+
addSchemeTypeName(name);
|
|
158
|
+
const typeName = capitalize(camelCase(name));
|
|
159
|
+
definedTypeNames.add(typeName);
|
|
160
|
+
const typeNode = wrapWithSchemeIfComponent(apiGen.getTypeFromSchema(def as OpenAPIV3.SchemaObject));
|
|
161
|
+
return factory.createTypeAliasDeclaration(
|
|
162
|
+
[factory.createModifier(ts.SyntaxKind.ExportKeyword)],
|
|
163
|
+
factory.createIdentifier(typeName),
|
|
164
|
+
undefined,
|
|
165
|
+
typeNode
|
|
166
|
+
);
|
|
167
|
+
});
|
|
167
168
|
return factory.createModuleDeclaration(
|
|
168
169
|
[factory.createModifier(ts.SyntaxKind.ExportKeyword)],
|
|
169
170
|
factory.createIdentifier('Scheme'),
|
|
@@ -174,12 +175,116 @@ export async function generateApi(
|
|
|
174
175
|
allTypeDefinitions.push(...componentDefinitions);
|
|
175
176
|
}
|
|
176
177
|
|
|
177
|
-
|
|
178
|
-
|
|
178
|
+
const enumEntries = [
|
|
179
|
+
...apiGen.enumAliases.filter(e => ts.isEnumDeclaration(e)),
|
|
180
|
+
...apiGen.enumAliases.filter(e => ts.isTypeAliasDeclaration(e)),
|
|
181
|
+
].map(enumDecl => {
|
|
182
|
+
if (ts.isEnumDeclaration(enumDecl)) {
|
|
183
|
+
return factory.createEnumDeclaration(
|
|
184
|
+
[factory.createModifier(ts.SyntaxKind.ExportKeyword)],
|
|
185
|
+
enumDecl.name,
|
|
186
|
+
enumDecl.members
|
|
187
|
+
);
|
|
188
|
+
} else if (ts.isTypeAliasDeclaration(enumDecl)) {
|
|
189
|
+
return factory.createTypeAliasDeclaration(
|
|
190
|
+
[factory.createModifier(ts.SyntaxKind.ExportKeyword)],
|
|
191
|
+
enumDecl.name,
|
|
192
|
+
enumDecl.typeParameters,
|
|
193
|
+
enumDecl.type
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
return enumDecl;
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
const unionTypeEnums = apiGen.aliases
|
|
200
|
+
.filter(alias => {
|
|
201
|
+
if (ts.isTypeAliasDeclaration(alias) && alias.type) {
|
|
202
|
+
return ts.isUnionTypeNode(alias.type);
|
|
203
|
+
}
|
|
204
|
+
return false;
|
|
205
|
+
})
|
|
206
|
+
.map(alias => {
|
|
207
|
+
if (ts.isTypeAliasDeclaration(alias)) {
|
|
208
|
+
return factory.createTypeAliasDeclaration(
|
|
209
|
+
[factory.createModifier(ts.SyntaxKind.ExportKeyword)],
|
|
210
|
+
alias.name,
|
|
211
|
+
alias.typeParameters,
|
|
212
|
+
alias.type
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
return alias;
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
const allEnumEntries = [...enumEntries, ...unionTypeEnums];
|
|
219
|
+
|
|
220
|
+
if (allEnumEntries.length > 0) {
|
|
221
|
+
allTypeDefinitions.push(
|
|
222
|
+
factory.createModuleDeclaration(
|
|
223
|
+
[factory.createModifier(ts.SyntaxKind.ExportKeyword)],
|
|
224
|
+
factory.createIdentifier('Enum'),
|
|
225
|
+
factory.createModuleBlock(allEnumEntries),
|
|
226
|
+
ts.NodeFlags.Namespace
|
|
227
|
+
)
|
|
228
|
+
);
|
|
179
229
|
}
|
|
180
230
|
|
|
181
|
-
|
|
231
|
+
if (apiGen.aliases.length > 0) {
|
|
232
|
+
const aliasEntries = apiGen.aliases
|
|
233
|
+
.filter(alias => {
|
|
234
|
+
if (ts.isTypeAliasDeclaration(alias)) {
|
|
235
|
+
const isDefinedInComponents = definedTypeNames.has(alias.name.text);
|
|
236
|
+
const isUnionTypeEnum = ts.isUnionTypeNode(alias.type);
|
|
237
|
+
return !isDefinedInComponents && !isUnionTypeEnum;
|
|
238
|
+
}
|
|
239
|
+
return false;
|
|
240
|
+
})
|
|
241
|
+
.map(alias => {
|
|
242
|
+
if (ts.isTypeAliasDeclaration(alias)) {
|
|
243
|
+
return factory.createTypeAliasDeclaration(
|
|
244
|
+
[factory.createModifier(ts.SyntaxKind.ExportKeyword)],
|
|
245
|
+
alias.name,
|
|
246
|
+
alias.typeParameters,
|
|
247
|
+
alias.type
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
return alias;
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
if (aliasEntries.length > 0) {
|
|
254
|
+
const existingSchemeIndex = allTypeDefinitions.findIndex(def =>
|
|
255
|
+
ts.isModuleDeclaration(def) &&
|
|
256
|
+
ts.isIdentifier(def.name) &&
|
|
257
|
+
def.name.text === 'Scheme'
|
|
258
|
+
);
|
|
259
|
+
|
|
260
|
+
if (existingSchemeIndex >= 0) {
|
|
261
|
+
const existingScheme = allTypeDefinitions[existingSchemeIndex] as ts.ModuleDeclaration;
|
|
262
|
+
const mergedMembers = [...(existingScheme.body as ts.ModuleBlock).statements, ...aliasEntries];
|
|
263
|
+
allTypeDefinitions[existingSchemeIndex] = factory.createModuleDeclaration(
|
|
264
|
+
[factory.createModifier(ts.SyntaxKind.ExportKeyword)],
|
|
265
|
+
factory.createIdentifier('Scheme'),
|
|
266
|
+
factory.createModuleBlock(mergedMembers),
|
|
267
|
+
ts.NodeFlags.Namespace
|
|
268
|
+
);
|
|
269
|
+
} else {
|
|
270
|
+
allTypeDefinitions.push(
|
|
271
|
+
factory.createModuleDeclaration(
|
|
272
|
+
[factory.createModifier(ts.SyntaxKind.ExportKeyword)],
|
|
273
|
+
factory.createIdentifier('Scheme'),
|
|
274
|
+
factory.createModuleBlock(aliasEntries),
|
|
275
|
+
ts.NodeFlags.Namespace
|
|
276
|
+
)
|
|
277
|
+
);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
182
281
|
|
|
282
|
+
const fs = await import('node:fs/promises');
|
|
283
|
+
const path = await import('node:path');
|
|
284
|
+
|
|
285
|
+
const sharedTypesDir = path.dirname(sharedTypesFile);
|
|
286
|
+
await fs.mkdir(sharedTypesDir, { recursive: true });
|
|
287
|
+
|
|
183
288
|
const output = printer.printNode(
|
|
184
289
|
ts.EmitHint.Unspecified,
|
|
185
290
|
factory.createSourceFile(
|
|
@@ -190,7 +295,6 @@ export async function generateApi(
|
|
|
190
295
|
resultFile
|
|
191
296
|
);
|
|
192
297
|
|
|
193
|
-
const fs = await import('node:fs/promises');
|
|
194
298
|
await fs.writeFile(sharedTypesFile, output, 'utf-8');
|
|
195
299
|
}
|
|
196
300
|
|
|
@@ -245,7 +349,12 @@ export async function generateApi(
|
|
|
245
349
|
[
|
|
246
350
|
generateImportNode(apiFile, { [apiImport]: 'api' }),
|
|
247
351
|
generateImportNode('@acrool/react-fetcher', { IRestFulEndpointsQueryReturn: 'IRestFulEndpointsQueryReturn' }),
|
|
248
|
-
...(sharedTypesFile ? [
|
|
352
|
+
...(sharedTypesFile ? [
|
|
353
|
+
generateImportNode(sharedTypesImportPath, {
|
|
354
|
+
Scheme: 'Scheme',
|
|
355
|
+
...(useEnumType ? { Enum: 'Enum' } : {})
|
|
356
|
+
})
|
|
357
|
+
] : []),
|
|
249
358
|
...(tag ? [generateTagTypes({ addTagTypes: extractAllTagTypes({ operationDefinitions }) })] : []),
|
|
250
359
|
generateCreateApiCall({
|
|
251
360
|
tag,
|
|
@@ -336,25 +445,6 @@ export async function generateApi(
|
|
|
336
445
|
)
|
|
337
446
|
.filter(([_1, _2, type]) => type !== keywordType.void)
|
|
338
447
|
.map(([code, response, type]) => {
|
|
339
|
-
if (sharedTypesFile && ts.isTypeReferenceNode(type) && type.typeName) {
|
|
340
|
-
if (ts.isIdentifier(type.typeName)) {
|
|
341
|
-
const typeName = type.typeName.text;
|
|
342
|
-
if (typeName in apiGen.aliases || typeName in apiGen.enumAliases) {
|
|
343
|
-
return ts.addSyntheticLeadingComment(
|
|
344
|
-
factory.createTypeReferenceNode(
|
|
345
|
-
factory.createQualifiedName(
|
|
346
|
-
factory.createIdentifier('sharedTypes'),
|
|
347
|
-
factory.createIdentifier(camelCase(typeName))
|
|
348
|
-
),
|
|
349
|
-
type.typeArguments
|
|
350
|
-
),
|
|
351
|
-
ts.SyntaxKind.MultiLineCommentTrivia,
|
|
352
|
-
`* status ${code} ${response.description} `,
|
|
353
|
-
false
|
|
354
|
-
);
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
448
|
return ts.addSyntheticLeadingComment(
|
|
359
449
|
type,
|
|
360
450
|
ts.SyntaxKind.MultiLineCommentTrivia,
|
|
@@ -620,6 +710,36 @@ export async function generateApi(
|
|
|
620
710
|
function wrapWithSchemeIfComponent(typeNode: ts.TypeNode): ts.TypeNode {
|
|
621
711
|
if (ts.isTypeReferenceNode(typeNode) && ts.isIdentifier(typeNode.typeName)) {
|
|
622
712
|
const typeName = typeNode.typeName.text;
|
|
713
|
+
|
|
714
|
+
// 檢查是否為 enum 類型(包括在 enumAliases 和 aliases 中的)
|
|
715
|
+
const isEnumType = useEnumType && (
|
|
716
|
+
apiGen.enumAliases.some(enumDecl => {
|
|
717
|
+
if (ts.isEnumDeclaration(enumDecl) || ts.isTypeAliasDeclaration(enumDecl)) {
|
|
718
|
+
return enumDecl.name.text === typeName;
|
|
719
|
+
}
|
|
720
|
+
return false;
|
|
721
|
+
}) ||
|
|
722
|
+
apiGen.aliases.some(alias => {
|
|
723
|
+
if (ts.isTypeAliasDeclaration(alias) && alias.type) {
|
|
724
|
+
// 檢查是否為 union type 的 enum
|
|
725
|
+
if (ts.isUnionTypeNode(alias.type)) {
|
|
726
|
+
return alias.name.text === typeName;
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
return false;
|
|
730
|
+
})
|
|
731
|
+
);
|
|
732
|
+
|
|
733
|
+
if (isEnumType) {
|
|
734
|
+
return factory.createTypeReferenceNode(
|
|
735
|
+
factory.createQualifiedName(
|
|
736
|
+
factory.createIdentifier('Enum'),
|
|
737
|
+
typeNode.typeName
|
|
738
|
+
),
|
|
739
|
+
typeNode.typeArguments?.map(wrapWithSchemeIfComponent)
|
|
740
|
+
);
|
|
741
|
+
}
|
|
742
|
+
|
|
623
743
|
if (schemeTypeNames.has(typeName)) {
|
|
624
744
|
return factory.createTypeReferenceNode(
|
|
625
745
|
factory.createQualifiedName(
|
|
@@ -640,6 +760,52 @@ export async function generateApi(
|
|
|
640
760
|
return factory.createArrayTypeNode(wrapWithSchemeIfComponent(typeNode.elementType));
|
|
641
761
|
}
|
|
642
762
|
if (ts.isUnionTypeNode(typeNode)) {
|
|
763
|
+
// 檢查是否為 enum 的 union type
|
|
764
|
+
const unionTypes = typeNode.types;
|
|
765
|
+
if (unionTypes.length > 0 && unionTypes.every(type =>
|
|
766
|
+
ts.isLiteralTypeNode(type) &&
|
|
767
|
+
(ts.isStringLiteral(type.literal) || ts.isNumericLiteral(type.literal))
|
|
768
|
+
)) {
|
|
769
|
+
// 這是一個 enum 的 union type,我們需要找到對應的 enum 類型
|
|
770
|
+
const enumValues = unionTypes.map(type => {
|
|
771
|
+
if (ts.isLiteralTypeNode(type)) {
|
|
772
|
+
if (ts.isStringLiteral(type.literal)) {
|
|
773
|
+
return type.literal.text;
|
|
774
|
+
} else if (ts.isNumericLiteral(type.literal)) {
|
|
775
|
+
return type.literal.text;
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
return null;
|
|
779
|
+
}).filter(Boolean);
|
|
780
|
+
|
|
781
|
+
// 查找對應的 enum 類型
|
|
782
|
+
const matchingEnum = apiGen.aliases.find(alias => {
|
|
783
|
+
if (ts.isTypeAliasDeclaration(alias) && ts.isUnionTypeNode(alias.type)) {
|
|
784
|
+
const aliasValues = alias.type.types.map(type => {
|
|
785
|
+
if (ts.isLiteralTypeNode(type)) {
|
|
786
|
+
if (ts.isStringLiteral(type.literal)) {
|
|
787
|
+
return type.literal.text;
|
|
788
|
+
} else if (ts.isNumericLiteral(type.literal)) {
|
|
789
|
+
return type.literal.text;
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
return null;
|
|
793
|
+
}).filter(Boolean);
|
|
794
|
+
|
|
795
|
+
return aliasValues.length === enumValues.length &&
|
|
796
|
+
aliasValues.every(val => enumValues.includes(val));
|
|
797
|
+
}
|
|
798
|
+
return false;
|
|
799
|
+
});
|
|
800
|
+
|
|
801
|
+
// 對於所有的 enum 類型,直接使用字串型別,不轉換為 Enum
|
|
802
|
+
// 這樣可以避免自動命名造成的變更問題
|
|
803
|
+
if (matchingEnum && ts.isTypeAliasDeclaration(matchingEnum)) {
|
|
804
|
+
// 直接返回原始的 union type,不轉換為 Enum
|
|
805
|
+
return typeNode;
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
|
|
643
809
|
return factory.createUnionTypeNode(typeNode.types.map(wrapWithSchemeIfComponent));
|
|
644
810
|
}
|
|
645
811
|
if (ts.isTypeLiteralNode(typeNode)) {
|