@acrool/rtk-query-codegen-openapi 1.3.0 → 1.4.0-alpha.1
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 +49 -41
- package/lib/bin/cli.mjs.map +1 -1
- package/lib/index.js +353 -35
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +353 -35
- package/lib/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/generators/component-schema-generator.ts +50 -1
- package/src/generators/types-generator.ts +159 -32
- package/src/services/unified-code-generator.ts +100 -14
- package/src/utils/schema-ref-analyzer.ts +218 -0
package/lib/index.js
CHANGED
|
@@ -108,7 +108,7 @@ init_cjs_shims();
|
|
|
108
108
|
// src/services/unified-code-generator.ts
|
|
109
109
|
init_cjs_shims();
|
|
110
110
|
var import_node_path4 = __toESM(require("node:path"));
|
|
111
|
-
var
|
|
111
|
+
var import_typescript4 = __toESM(require("typescript"));
|
|
112
112
|
|
|
113
113
|
// src/services/openapi-service.ts
|
|
114
114
|
init_cjs_shims();
|
|
@@ -514,7 +514,28 @@ function renameIdentifier(node, oldName, newName) {
|
|
|
514
514
|
})
|
|
515
515
|
]).transformed[0];
|
|
516
516
|
}
|
|
517
|
-
function
|
|
517
|
+
function isStringEnumType(node) {
|
|
518
|
+
if (!import_typescript.default.isUnionTypeNode(node.type)) return null;
|
|
519
|
+
const members = [];
|
|
520
|
+
for (const member of node.type.types) {
|
|
521
|
+
if (import_typescript.default.isLiteralTypeNode(member) && import_typescript.default.isStringLiteral(member.literal)) {
|
|
522
|
+
members.push(member.literal.text);
|
|
523
|
+
} else {
|
|
524
|
+
return null;
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
return members.length > 0 ? members : null;
|
|
528
|
+
}
|
|
529
|
+
function generateEnumDeclaration(name, members) {
|
|
530
|
+
const enumMembers = members.map((value) => {
|
|
531
|
+
const key = value.charAt(0).toUpperCase() + value.slice(1);
|
|
532
|
+
return ` ${key} = "${value}"`;
|
|
533
|
+
});
|
|
534
|
+
return `export enum ${name} {
|
|
535
|
+
${enumMembers.join(",\n")}
|
|
536
|
+
}`;
|
|
537
|
+
}
|
|
538
|
+
function generateComponentSchemaFile(interfaces, includeOnly) {
|
|
518
539
|
const printer = import_typescript.default.createPrinter({ newLine: import_typescript.default.NewLineKind.LineFeed });
|
|
519
540
|
const resultFile = import_typescript.default.createSourceFile(
|
|
520
541
|
"component-schema.ts",
|
|
@@ -528,6 +549,16 @@ function generateComponentSchemaFile(interfaces) {
|
|
|
528
549
|
Object.entries(interfaces).forEach(([originalName, node]) => {
|
|
529
550
|
const pascalCaseName = toPascalCase(originalName);
|
|
530
551
|
typeNameMapping[originalName] = pascalCaseName;
|
|
552
|
+
if (includeOnly && !includeOnly.has(originalName)) {
|
|
553
|
+
return;
|
|
554
|
+
}
|
|
555
|
+
if (import_typescript.default.isTypeAliasDeclaration(node)) {
|
|
556
|
+
const enumMembers = isStringEnumType(node);
|
|
557
|
+
if (enumMembers) {
|
|
558
|
+
renamedInterfaces.push(generateEnumDeclaration(pascalCaseName, enumMembers));
|
|
559
|
+
return;
|
|
560
|
+
}
|
|
561
|
+
}
|
|
531
562
|
const renamedNode = renameIdentifier(node, originalName, pascalCaseName);
|
|
532
563
|
const printed = printer.printNode(import_typescript.default.EmitHint.Unspecified, renamedNode, resultFile);
|
|
533
564
|
renamedInterfaces.push(printed);
|
|
@@ -566,7 +597,7 @@ function generateDoNotModifyFile() {
|
|
|
566
597
|
|
|
567
598
|
// src/services/api-code-generator.ts
|
|
568
599
|
init_cjs_shims();
|
|
569
|
-
var
|
|
600
|
+
var import_typescript3 = __toESM(require("typescript"));
|
|
570
601
|
|
|
571
602
|
// src/services/endpoint-info-extractor.ts
|
|
572
603
|
init_cjs_shims();
|
|
@@ -668,10 +699,67 @@ var EndpointInfoExtractor = class {
|
|
|
668
699
|
|
|
669
700
|
// src/generators/types-generator.ts
|
|
670
701
|
init_cjs_shims();
|
|
702
|
+
var import_typescript2 = __toESM(require("typescript"));
|
|
671
703
|
var toPascalCase2 = (name) => {
|
|
672
704
|
return name.charAt(0).toUpperCase() + name.slice(1);
|
|
673
705
|
};
|
|
674
|
-
function
|
|
706
|
+
function renameIdentifier2(node, oldName, newName) {
|
|
707
|
+
return import_typescript2.default.transform(node, [
|
|
708
|
+
(context) => (rootNode) => import_typescript2.default.visitNode(rootNode, function visit(node2) {
|
|
709
|
+
if (import_typescript2.default.isIdentifier(node2) && node2.text === oldName) {
|
|
710
|
+
return import_typescript2.default.factory.createIdentifier(newName);
|
|
711
|
+
}
|
|
712
|
+
return import_typescript2.default.visitEachChild(node2, visit, context);
|
|
713
|
+
})
|
|
714
|
+
]).transformed[0];
|
|
715
|
+
}
|
|
716
|
+
function prefixSharedSchemaRefs(node, allSchemaNames, localSchemaNames, declarationName) {
|
|
717
|
+
const sharedNames = /* @__PURE__ */ new Set();
|
|
718
|
+
for (const name of allSchemaNames) {
|
|
719
|
+
if (!localSchemaNames.has(name)) {
|
|
720
|
+
sharedNames.add(toPascalCase2(name));
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
return import_typescript2.default.transform(node, [
|
|
724
|
+
(context) => (rootNode) => import_typescript2.default.visitNode(rootNode, function visit(node2) {
|
|
725
|
+
if (import_typescript2.default.isTypeReferenceNode(node2) && import_typescript2.default.isIdentifier(node2.typeName)) {
|
|
726
|
+
const name = node2.typeName.text;
|
|
727
|
+
if (sharedNames.has(name) && name !== declarationName) {
|
|
728
|
+
const qualifiedName = import_typescript2.default.factory.createQualifiedName(
|
|
729
|
+
import_typescript2.default.factory.createIdentifier("Schema"),
|
|
730
|
+
import_typescript2.default.factory.createIdentifier(name)
|
|
731
|
+
);
|
|
732
|
+
return import_typescript2.default.factory.createTypeReferenceNode(qualifiedName, node2.typeArguments);
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
return import_typescript2.default.visitEachChild(node2, visit, context);
|
|
736
|
+
})
|
|
737
|
+
]).transformed[0];
|
|
738
|
+
}
|
|
739
|
+
function isStringEnumType2(node) {
|
|
740
|
+
if (!import_typescript2.default.isUnionTypeNode(node.type)) return null;
|
|
741
|
+
const members = [];
|
|
742
|
+
for (const member of node.type.types) {
|
|
743
|
+
if (import_typescript2.default.isLiteralTypeNode(member) && import_typescript2.default.isStringLiteral(member.literal)) {
|
|
744
|
+
members.push(member.literal.text);
|
|
745
|
+
} else {
|
|
746
|
+
return null;
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
return members.length > 0 ? members : null;
|
|
750
|
+
}
|
|
751
|
+
function generateEnumDeclaration2(name, members) {
|
|
752
|
+
const enumMembers = members.map((value) => {
|
|
753
|
+
const key = value.charAt(0).toUpperCase() + value.slice(1);
|
|
754
|
+
return ` ${key} = "${value}"`;
|
|
755
|
+
});
|
|
756
|
+
return `export enum ${name} {
|
|
757
|
+
${enumMembers.join(",\n")}
|
|
758
|
+
}`;
|
|
759
|
+
}
|
|
760
|
+
function generateTypesFile(endpointInfos, _options, schemaInterfaces, operationDefinitions, localSchemaOptions) {
|
|
761
|
+
const localSchemaNames = localSchemaOptions?.localSchemaNames ?? /* @__PURE__ */ new Set();
|
|
762
|
+
const localSchemaInterfaces = localSchemaOptions?.localSchemaInterfaces ?? {};
|
|
675
763
|
const schemaTypeMap = {};
|
|
676
764
|
if (schemaInterfaces) {
|
|
677
765
|
Object.keys(schemaInterfaces).forEach((actualTypeName) => {
|
|
@@ -686,23 +774,48 @@ function generateTypesFile(endpointInfos, _options, schemaInterfaces, operationD
|
|
|
686
774
|
}
|
|
687
775
|
});
|
|
688
776
|
}
|
|
777
|
+
const hasSharedSchemaTypes = schemaInterfaces && Object.keys(schemaInterfaces).some(
|
|
778
|
+
(name) => !localSchemaNames.has(name)
|
|
779
|
+
);
|
|
689
780
|
let importStatement = `/* eslint-disable */
|
|
690
|
-
// [Warning] Generated automatically - do not edit manually
|
|
691
|
-
|
|
781
|
+
// [Warning] Generated automatically - do not edit manually
|
|
782
|
+
|
|
692
783
|
`;
|
|
693
|
-
|
|
694
|
-
if (hasSchemaTypes) {
|
|
784
|
+
if (hasSharedSchemaTypes) {
|
|
695
785
|
importStatement += `import * as Schema from "../schema";
|
|
696
786
|
`;
|
|
697
787
|
}
|
|
698
788
|
importStatement += "\n";
|
|
699
789
|
const typeDefinitions = [];
|
|
790
|
+
if (Object.keys(localSchemaInterfaces).length > 0) {
|
|
791
|
+
const printer = import_typescript2.default.createPrinter({ newLine: import_typescript2.default.NewLineKind.LineFeed });
|
|
792
|
+
const resultFile = import_typescript2.default.createSourceFile("types.ts", "", import_typescript2.default.ScriptTarget.Latest, false, import_typescript2.default.ScriptKind.TS);
|
|
793
|
+
const localTypeDefs = [];
|
|
794
|
+
const allSchemaNameSet = new Set(schemaInterfaces ? Object.keys(schemaInterfaces) : []);
|
|
795
|
+
for (const [originalName, node] of Object.entries(localSchemaInterfaces)) {
|
|
796
|
+
const pascalCaseName = toPascalCase2(originalName);
|
|
797
|
+
if (import_typescript2.default.isTypeAliasDeclaration(node)) {
|
|
798
|
+
const enumMembers = isStringEnumType2(node);
|
|
799
|
+
if (enumMembers) {
|
|
800
|
+
localTypeDefs.push(generateEnumDeclaration2(pascalCaseName, enumMembers));
|
|
801
|
+
continue;
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
let transformedNode = renameIdentifier2(node, originalName, pascalCaseName);
|
|
805
|
+
transformedNode = prefixSharedSchemaRefs(transformedNode, allSchemaNameSet, localSchemaNames, pascalCaseName);
|
|
806
|
+
const printed = printer.printNode(import_typescript2.default.EmitHint.Unspecified, transformedNode, resultFile);
|
|
807
|
+
localTypeDefs.push(printed);
|
|
808
|
+
}
|
|
809
|
+
if (localTypeDefs.length > 0) {
|
|
810
|
+
typeDefinitions.push(localTypeDefs.join("\n"));
|
|
811
|
+
}
|
|
812
|
+
}
|
|
700
813
|
const endpointTypes = [];
|
|
701
814
|
endpointInfos.forEach((endpoint) => {
|
|
702
815
|
const reqTypeName = endpoint.argTypeName;
|
|
703
816
|
const resTypeName = endpoint.responseTypeName;
|
|
704
817
|
if (reqTypeName) {
|
|
705
|
-
const requestTypeContent = generateRequestTypeContent(endpoint, operationDefinitions, schemaTypeMap);
|
|
818
|
+
const requestTypeContent = generateRequestTypeContent(endpoint, operationDefinitions, schemaTypeMap, localSchemaNames);
|
|
706
819
|
if (requestTypeContent.trim() === "") {
|
|
707
820
|
endpointTypes.push(
|
|
708
821
|
`export type ${reqTypeName} = void;`,
|
|
@@ -718,7 +831,7 @@ function generateTypesFile(endpointInfos, _options, schemaInterfaces, operationD
|
|
|
718
831
|
}
|
|
719
832
|
}
|
|
720
833
|
if (resTypeName) {
|
|
721
|
-
const responseTypeResult = generateResponseTypeContent(endpoint, operationDefinitions, schemaTypeMap);
|
|
834
|
+
const responseTypeResult = generateResponseTypeContent(endpoint, operationDefinitions, schemaTypeMap, localSchemaNames);
|
|
722
835
|
if (responseTypeResult.content.trim() === "") {
|
|
723
836
|
endpointTypes.push(
|
|
724
837
|
`export type ${resTypeName} = void;`,
|
|
@@ -751,19 +864,19 @@ function generateTypesFile(endpointInfos, _options, schemaInterfaces, operationD
|
|
|
751
864
|
}
|
|
752
865
|
return importStatement + typeDefinitions.join("\n\n");
|
|
753
866
|
}
|
|
754
|
-
function generateRequestTypeContent(endpoint, operationDefinitions, schemaTypeMap = {}) {
|
|
867
|
+
function generateRequestTypeContent(endpoint, operationDefinitions, schemaTypeMap = {}, localSchemaNames = /* @__PURE__ */ new Set()) {
|
|
755
868
|
const properties = [];
|
|
756
869
|
if (endpoint.queryParams && endpoint.queryParams.length > 0) {
|
|
757
870
|
endpoint.queryParams.forEach((param) => {
|
|
758
871
|
const optional = param.required ? "" : "?";
|
|
759
|
-
const paramType = getTypeFromParameter(param, schemaTypeMap);
|
|
872
|
+
const paramType = getTypeFromParameter(param, schemaTypeMap, localSchemaNames);
|
|
760
873
|
properties.push(` ${param.name}${optional}: ${paramType};`);
|
|
761
874
|
});
|
|
762
875
|
}
|
|
763
876
|
if (endpoint.pathParams && endpoint.pathParams.length > 0) {
|
|
764
877
|
endpoint.pathParams.forEach((param) => {
|
|
765
878
|
const optional = param.required ? "" : "?";
|
|
766
|
-
const paramType = getTypeFromParameter(param, schemaTypeMap);
|
|
879
|
+
const paramType = getTypeFromParameter(param, schemaTypeMap, localSchemaNames);
|
|
767
880
|
properties.push(` ${param.name}${optional}: ${paramType};`);
|
|
768
881
|
});
|
|
769
882
|
}
|
|
@@ -777,15 +890,15 @@ function generateRequestTypeContent(endpoint, operationDefinitions, schemaTypeMa
|
|
|
777
890
|
const jsonContent = content["application/json"] || content["*/*"];
|
|
778
891
|
const formContent = content["multipart/form-data"] || content["application/x-www-form-urlencoded"];
|
|
779
892
|
if (jsonContent?.schema) {
|
|
780
|
-
const bodyType = getTypeFromSchema(jsonContent.schema, schemaTypeMap, 1);
|
|
893
|
+
const bodyType = getTypeFromSchema(jsonContent.schema, schemaTypeMap, 1, localSchemaNames);
|
|
781
894
|
properties.push(` body: ${bodyType};`);
|
|
782
895
|
} else if (formContent?.schema) {
|
|
783
|
-
const bodyType = getTypeFromSchema(formContent.schema, schemaTypeMap, 1);
|
|
896
|
+
const bodyType = getTypeFromSchema(formContent.schema, schemaTypeMap, 1, localSchemaNames);
|
|
784
897
|
properties.push(` body: ${bodyType};`);
|
|
785
898
|
} else {
|
|
786
899
|
const firstContent = Object.values(content)[0];
|
|
787
900
|
if (firstContent?.schema) {
|
|
788
|
-
const bodyType = getTypeFromSchema(firstContent.schema, schemaTypeMap, 1);
|
|
901
|
+
const bodyType = getTypeFromSchema(firstContent.schema, schemaTypeMap, 1, localSchemaNames);
|
|
789
902
|
properties.push(` body: ${bodyType};`);
|
|
790
903
|
} else {
|
|
791
904
|
properties.push(` body?: any; // Request body from OpenAPI`);
|
|
@@ -797,7 +910,7 @@ function generateRequestTypeContent(endpoint, operationDefinitions, schemaTypeMa
|
|
|
797
910
|
}
|
|
798
911
|
return properties.join("\n");
|
|
799
912
|
}
|
|
800
|
-
function generateResponseTypeContent(endpoint, operationDefinitions, schemaTypeMap = {}) {
|
|
913
|
+
function generateResponseTypeContent(endpoint, operationDefinitions, schemaTypeMap = {}, localSchemaNames = /* @__PURE__ */ new Set()) {
|
|
801
914
|
const operationDef = operationDefinitions?.find((op) => {
|
|
802
915
|
return op.operation?.operationId === endpoint.operationName || op.operation?.operationId === endpoint.operationName.toLowerCase() || // 也嘗試匹配 verb + path 組合
|
|
803
916
|
op.verb === endpoint.verb.toLowerCase() && op.path === endpoint.path;
|
|
@@ -809,12 +922,12 @@ function generateResponseTypeContent(endpoint, operationDefinitions, schemaTypeM
|
|
|
809
922
|
if (jsonContent?.schema) {
|
|
810
923
|
const schema = jsonContent.schema;
|
|
811
924
|
if (schema.$ref || schema.type !== "object" || !schema.properties) {
|
|
812
|
-
const directType = getTypeFromSchema(schema, schemaTypeMap, 0);
|
|
925
|
+
const directType = getTypeFromSchema(schema, schemaTypeMap, 0, localSchemaNames);
|
|
813
926
|
if (directType && directType !== "any") {
|
|
814
927
|
return { content: directType, isDirectType: true };
|
|
815
928
|
}
|
|
816
929
|
}
|
|
817
|
-
const responseProps = parseSchemaProperties(schema, schemaTypeMap);
|
|
930
|
+
const responseProps = parseSchemaProperties(schema, schemaTypeMap, localSchemaNames);
|
|
818
931
|
if (responseProps.length > 0) {
|
|
819
932
|
return { content: responseProps.join("\n"), isDirectType: false };
|
|
820
933
|
}
|
|
@@ -823,14 +936,14 @@ function generateResponseTypeContent(endpoint, operationDefinitions, schemaTypeM
|
|
|
823
936
|
}
|
|
824
937
|
return { content: "", isDirectType: false };
|
|
825
938
|
}
|
|
826
|
-
function parseSchemaProperties(schema, schemaTypeMap = {}) {
|
|
939
|
+
function parseSchemaProperties(schema, schemaTypeMap = {}, localSchemaNames = /* @__PURE__ */ new Set()) {
|
|
827
940
|
const properties = [];
|
|
828
941
|
if (schema.type === "object" && schema.properties) {
|
|
829
942
|
const required = schema.required || [];
|
|
830
943
|
Object.entries(schema.properties).forEach(([propName, propSchema]) => {
|
|
831
944
|
const isRequired = required.includes(propName);
|
|
832
945
|
const optional = isRequired ? "" : "?";
|
|
833
|
-
const propType = getTypeFromSchema(propSchema, schemaTypeMap, 1);
|
|
946
|
+
const propType = getTypeFromSchema(propSchema, schemaTypeMap, 1, localSchemaNames);
|
|
834
947
|
const needsQuotes = /[^a-zA-Z0-9_$]/.test(propName);
|
|
835
948
|
const quotedPropName = needsQuotes ? `"${propName}"` : propName;
|
|
836
949
|
if (propSchema.description) {
|
|
@@ -841,7 +954,7 @@ function parseSchemaProperties(schema, schemaTypeMap = {}) {
|
|
|
841
954
|
}
|
|
842
955
|
return properties;
|
|
843
956
|
}
|
|
844
|
-
function getTypeFromSchema(schema, schemaTypeMap = {}, indentLevel = 0) {
|
|
957
|
+
function getTypeFromSchema(schema, schemaTypeMap = {}, indentLevel = 0, localSchemaNames = /* @__PURE__ */ new Set()) {
|
|
845
958
|
if (!schema) return "any";
|
|
846
959
|
if (schema.$ref) {
|
|
847
960
|
const refPath = schema.$ref;
|
|
@@ -849,7 +962,7 @@ function getTypeFromSchema(schema, schemaTypeMap = {}, indentLevel = 0) {
|
|
|
849
962
|
const originalTypeName = refPath.replace("#/components/schemas/", "");
|
|
850
963
|
const actualTypeName = schemaTypeMap[originalTypeName] || originalTypeName;
|
|
851
964
|
const pascalCaseTypeName = toPascalCase2(actualTypeName);
|
|
852
|
-
const baseType2 = `Schema.${pascalCaseTypeName}`;
|
|
965
|
+
const baseType2 = localSchemaNames.has(originalTypeName) ? pascalCaseTypeName : `Schema.${pascalCaseTypeName}`;
|
|
853
966
|
return schema.nullable ? `${baseType2} | null` : baseType2;
|
|
854
967
|
}
|
|
855
968
|
}
|
|
@@ -872,7 +985,7 @@ function getTypeFromSchema(schema, schemaTypeMap = {}, indentLevel = 0) {
|
|
|
872
985
|
baseType = "boolean";
|
|
873
986
|
break;
|
|
874
987
|
case "array":
|
|
875
|
-
const itemType = schema.items ? getTypeFromSchema(schema.items, schemaTypeMap, indentLevel) : "any";
|
|
988
|
+
const itemType = schema.items ? getTypeFromSchema(schema.items, schemaTypeMap, indentLevel, localSchemaNames) : "any";
|
|
876
989
|
const needsParentheses = itemType.includes("|");
|
|
877
990
|
baseType = needsParentheses ? `(${itemType})[]` : `${itemType}[]`;
|
|
878
991
|
break;
|
|
@@ -881,7 +994,7 @@ function getTypeFromSchema(schema, schemaTypeMap = {}, indentLevel = 0) {
|
|
|
881
994
|
const entries = Object.entries(schema.properties);
|
|
882
995
|
if (entries.length === 0) {
|
|
883
996
|
if (schema.additionalProperties) {
|
|
884
|
-
const valueType = schema.additionalProperties === true ? "any" : getTypeFromSchema(schema.additionalProperties, schemaTypeMap, indentLevel);
|
|
997
|
+
const valueType = schema.additionalProperties === true ? "any" : getTypeFromSchema(schema.additionalProperties, schemaTypeMap, indentLevel, localSchemaNames);
|
|
885
998
|
baseType = `Record<string, ${valueType}>`;
|
|
886
999
|
} else {
|
|
887
1000
|
baseType = "{}";
|
|
@@ -893,7 +1006,7 @@ function getTypeFromSchema(schema, schemaTypeMap = {}, indentLevel = 0) {
|
|
|
893
1006
|
entries.forEach(([key, propSchema]) => {
|
|
894
1007
|
const required = schema.required || [];
|
|
895
1008
|
const optional = required.includes(key) ? "" : "?";
|
|
896
|
-
const type = getTypeFromSchema(propSchema, schemaTypeMap, indentLevel + 1);
|
|
1009
|
+
const type = getTypeFromSchema(propSchema, schemaTypeMap, indentLevel + 1, localSchemaNames);
|
|
897
1010
|
const needsQuotes = /[^a-zA-Z0-9_$]/.test(key);
|
|
898
1011
|
const quotedKey = needsQuotes ? `"${key}"` : key;
|
|
899
1012
|
if (propSchema.description) {
|
|
@@ -906,7 +1019,7 @@ ${props.join("\n")}
|
|
|
906
1019
|
${currentIndent}}`;
|
|
907
1020
|
}
|
|
908
1021
|
} else if (schema.additionalProperties) {
|
|
909
|
-
const valueType = schema.additionalProperties === true ? "any" : getTypeFromSchema(schema.additionalProperties, schemaTypeMap, indentLevel);
|
|
1022
|
+
const valueType = schema.additionalProperties === true ? "any" : getTypeFromSchema(schema.additionalProperties, schemaTypeMap, indentLevel, localSchemaNames);
|
|
910
1023
|
baseType = `Record<string, ${valueType}>`;
|
|
911
1024
|
} else {
|
|
912
1025
|
baseType = "any";
|
|
@@ -918,9 +1031,9 @@ ${currentIndent}}`;
|
|
|
918
1031
|
}
|
|
919
1032
|
return schema.nullable ? `${baseType} | null` : baseType;
|
|
920
1033
|
}
|
|
921
|
-
function getTypeFromParameter(param, schemaTypeMap = {}) {
|
|
1034
|
+
function getTypeFromParameter(param, schemaTypeMap = {}, localSchemaNames = /* @__PURE__ */ new Set()) {
|
|
922
1035
|
if (!param.schema) return "any";
|
|
923
|
-
return getTypeFromSchema(param.schema, schemaTypeMap);
|
|
1036
|
+
return getTypeFromSchema(param.schema, schemaTypeMap, 0, localSchemaNames);
|
|
924
1037
|
}
|
|
925
1038
|
|
|
926
1039
|
// src/generators/rtk-query-generator.ts
|
|
@@ -1117,7 +1230,7 @@ var ApiCodeGenerator = class {
|
|
|
1117
1230
|
};
|
|
1118
1231
|
const apiGen = this.parserService.getApiGenerator();
|
|
1119
1232
|
const schemaInterfaces = apiGen.aliases.reduce((curr, alias) => {
|
|
1120
|
-
if (
|
|
1233
|
+
if (import_typescript3.default.isInterfaceDeclaration(alias) || import_typescript3.default.isTypeAliasDeclaration(alias)) {
|
|
1121
1234
|
const name = alias.name.text;
|
|
1122
1235
|
return {
|
|
1123
1236
|
...curr,
|
|
@@ -1201,6 +1314,150 @@ ${enumEntries}
|
|
|
1201
1314
|
`;
|
|
1202
1315
|
}
|
|
1203
1316
|
|
|
1317
|
+
// src/utils/schema-ref-analyzer.ts
|
|
1318
|
+
init_cjs_shims();
|
|
1319
|
+
function collectRefsFromSchema(schema, refs) {
|
|
1320
|
+
if (!schema || typeof schema !== "object") return;
|
|
1321
|
+
if (schema.$ref && typeof schema.$ref === "string") {
|
|
1322
|
+
const match = schema.$ref.match(/^#\/components\/schemas\/(.+)$/);
|
|
1323
|
+
if (match) {
|
|
1324
|
+
refs.add(match[1]);
|
|
1325
|
+
}
|
|
1326
|
+
}
|
|
1327
|
+
if (schema.properties) {
|
|
1328
|
+
for (const prop of Object.values(schema.properties)) {
|
|
1329
|
+
collectRefsFromSchema(prop, refs);
|
|
1330
|
+
}
|
|
1331
|
+
}
|
|
1332
|
+
if (schema.items) {
|
|
1333
|
+
collectRefsFromSchema(schema.items, refs);
|
|
1334
|
+
}
|
|
1335
|
+
if (schema.additionalProperties && typeof schema.additionalProperties === "object") {
|
|
1336
|
+
collectRefsFromSchema(schema.additionalProperties, refs);
|
|
1337
|
+
}
|
|
1338
|
+
for (const key of ["allOf", "oneOf", "anyOf"]) {
|
|
1339
|
+
if (Array.isArray(schema[key])) {
|
|
1340
|
+
for (const item of schema[key]) {
|
|
1341
|
+
collectRefsFromSchema(item, refs);
|
|
1342
|
+
}
|
|
1343
|
+
}
|
|
1344
|
+
}
|
|
1345
|
+
}
|
|
1346
|
+
function collectDirectRefs(operationDefs) {
|
|
1347
|
+
const refs = /* @__PURE__ */ new Set();
|
|
1348
|
+
for (const opDef of operationDefs) {
|
|
1349
|
+
const op = opDef.operation;
|
|
1350
|
+
if (op.parameters) {
|
|
1351
|
+
for (const param of op.parameters) {
|
|
1352
|
+
const p = param;
|
|
1353
|
+
if (p.schema) {
|
|
1354
|
+
collectRefsFromSchema(p.schema, refs);
|
|
1355
|
+
}
|
|
1356
|
+
}
|
|
1357
|
+
}
|
|
1358
|
+
if (op.requestBody) {
|
|
1359
|
+
const rb = op.requestBody;
|
|
1360
|
+
if (rb.content) {
|
|
1361
|
+
for (const ct of Object.values(rb.content)) {
|
|
1362
|
+
if (ct.schema) {
|
|
1363
|
+
collectRefsFromSchema(ct.schema, refs);
|
|
1364
|
+
}
|
|
1365
|
+
}
|
|
1366
|
+
}
|
|
1367
|
+
}
|
|
1368
|
+
if (op.responses) {
|
|
1369
|
+
for (const resp of Object.values(op.responses)) {
|
|
1370
|
+
const r = resp;
|
|
1371
|
+
if (r.content) {
|
|
1372
|
+
for (const ct of Object.values(r.content)) {
|
|
1373
|
+
if (ct.schema) {
|
|
1374
|
+
collectRefsFromSchema(ct.schema, refs);
|
|
1375
|
+
}
|
|
1376
|
+
}
|
|
1377
|
+
}
|
|
1378
|
+
}
|
|
1379
|
+
}
|
|
1380
|
+
}
|
|
1381
|
+
return refs;
|
|
1382
|
+
}
|
|
1383
|
+
function resolveTransitiveDeps(directRefs, allSchemas) {
|
|
1384
|
+
const resolved = /* @__PURE__ */ new Set();
|
|
1385
|
+
const queue = [...directRefs];
|
|
1386
|
+
while (queue.length > 0) {
|
|
1387
|
+
const name = queue.pop();
|
|
1388
|
+
if (resolved.has(name)) continue;
|
|
1389
|
+
resolved.add(name);
|
|
1390
|
+
const schema = allSchemas[name];
|
|
1391
|
+
if (!schema) continue;
|
|
1392
|
+
const nestedRefs = /* @__PURE__ */ new Set();
|
|
1393
|
+
collectRefsFromSchema(schema, nestedRefs);
|
|
1394
|
+
for (const ref of nestedRefs) {
|
|
1395
|
+
if (!resolved.has(ref)) {
|
|
1396
|
+
queue.push(ref);
|
|
1397
|
+
}
|
|
1398
|
+
}
|
|
1399
|
+
}
|
|
1400
|
+
return resolved;
|
|
1401
|
+
}
|
|
1402
|
+
function analyzeSchemaRefs(groupOperations, allSchemas, allSchemaNames) {
|
|
1403
|
+
const groupRefs = /* @__PURE__ */ new Map();
|
|
1404
|
+
for (const [groupKey, opDefs] of groupOperations) {
|
|
1405
|
+
const directRefs = collectDirectRefs(opDefs);
|
|
1406
|
+
const fullRefs = resolveTransitiveDeps(directRefs, allSchemas);
|
|
1407
|
+
groupRefs.set(groupKey, fullRefs);
|
|
1408
|
+
}
|
|
1409
|
+
const refCountMap = /* @__PURE__ */ new Map();
|
|
1410
|
+
for (const [groupKey, refs] of groupRefs) {
|
|
1411
|
+
for (const schemaName of refs) {
|
|
1412
|
+
if (!refCountMap.has(schemaName)) {
|
|
1413
|
+
refCountMap.set(schemaName, /* @__PURE__ */ new Set());
|
|
1414
|
+
}
|
|
1415
|
+
refCountMap.get(schemaName).add(groupKey);
|
|
1416
|
+
}
|
|
1417
|
+
}
|
|
1418
|
+
const sharedSchemas = /* @__PURE__ */ new Set();
|
|
1419
|
+
const groupLocalSchemas = /* @__PURE__ */ new Map();
|
|
1420
|
+
const unusedSchemas = /* @__PURE__ */ new Set();
|
|
1421
|
+
for (const schemaName of allSchemaNames) {
|
|
1422
|
+
const groups = refCountMap.get(schemaName);
|
|
1423
|
+
if (!groups || groups.size === 0) {
|
|
1424
|
+
unusedSchemas.add(schemaName);
|
|
1425
|
+
} else if (groups.size === 1) {
|
|
1426
|
+
const groupKey = [...groups][0];
|
|
1427
|
+
if (!groupLocalSchemas.has(groupKey)) {
|
|
1428
|
+
groupLocalSchemas.set(groupKey, /* @__PURE__ */ new Set());
|
|
1429
|
+
}
|
|
1430
|
+
groupLocalSchemas.get(groupKey).add(schemaName);
|
|
1431
|
+
} else {
|
|
1432
|
+
sharedSchemas.add(schemaName);
|
|
1433
|
+
}
|
|
1434
|
+
}
|
|
1435
|
+
let changed = true;
|
|
1436
|
+
while (changed) {
|
|
1437
|
+
changed = false;
|
|
1438
|
+
for (const [groupKey, localSchemas] of groupLocalSchemas) {
|
|
1439
|
+
for (const schemaName of [...localSchemas]) {
|
|
1440
|
+
const schema = allSchemas[schemaName];
|
|
1441
|
+
if (!schema) continue;
|
|
1442
|
+
const deps = /* @__PURE__ */ new Set();
|
|
1443
|
+
collectRefsFromSchema(schema, deps);
|
|
1444
|
+
for (const dep of deps) {
|
|
1445
|
+
for (const [otherGroup, otherLocals] of groupLocalSchemas) {
|
|
1446
|
+
if (otherGroup !== groupKey && otherLocals.has(dep)) {
|
|
1447
|
+
sharedSchemas.add(dep);
|
|
1448
|
+
sharedSchemas.add(schemaName);
|
|
1449
|
+
otherLocals.delete(dep);
|
|
1450
|
+
localSchemas.delete(schemaName);
|
|
1451
|
+
changed = true;
|
|
1452
|
+
}
|
|
1453
|
+
}
|
|
1454
|
+
}
|
|
1455
|
+
}
|
|
1456
|
+
}
|
|
1457
|
+
}
|
|
1458
|
+
return { sharedSchemas, groupLocalSchemas, unusedSchemas };
|
|
1459
|
+
}
|
|
1460
|
+
|
|
1204
1461
|
// src/services/unified-code-generator.ts
|
|
1205
1462
|
var UnifiedCodeGenerator = class {
|
|
1206
1463
|
_options;
|
|
@@ -1223,6 +1480,10 @@ var UnifiedCodeGenerator = class {
|
|
|
1223
1480
|
};
|
|
1224
1481
|
// 收集所有 tags
|
|
1225
1482
|
allTags = /* @__PURE__ */ new Set();
|
|
1483
|
+
// 收集每個 group 的 operation definitions(用於 schema 引用分析)
|
|
1484
|
+
groupOperationDefs = /* @__PURE__ */ new Map();
|
|
1485
|
+
// 收集每個 group 的生成選項(用於重新生成 types)
|
|
1486
|
+
groupGenerationOptions = /* @__PURE__ */ new Map();
|
|
1226
1487
|
constructor(options) {
|
|
1227
1488
|
this._options = options;
|
|
1228
1489
|
}
|
|
@@ -1232,6 +1493,7 @@ var UnifiedCodeGenerator = class {
|
|
|
1232
1493
|
async generateAll() {
|
|
1233
1494
|
await this.prepare();
|
|
1234
1495
|
await this.generateApi();
|
|
1496
|
+
this.splitSchemaByUsage();
|
|
1235
1497
|
this.generateCommonTypesContent();
|
|
1236
1498
|
this.generateSchemaContent();
|
|
1237
1499
|
this.generateUtilsContent();
|
|
@@ -1258,7 +1520,7 @@ var UnifiedCodeGenerator = class {
|
|
|
1258
1520
|
this.parserService.initialize();
|
|
1259
1521
|
const apiGen = this.parserService.getApiGenerator();
|
|
1260
1522
|
this.schemaInterfaces = apiGen.aliases.reduce((curr, alias) => {
|
|
1261
|
-
if (
|
|
1523
|
+
if (import_typescript4.default.isInterfaceDeclaration(alias) || import_typescript4.default.isTypeAliasDeclaration(alias)) {
|
|
1262
1524
|
const name = alias.name.text;
|
|
1263
1525
|
return {
|
|
1264
1526
|
...curr,
|
|
@@ -1298,6 +1560,55 @@ var UnifiedCodeGenerator = class {
|
|
|
1298
1560
|
}
|
|
1299
1561
|
}
|
|
1300
1562
|
}
|
|
1563
|
+
/**
|
|
1564
|
+
* 分析 schema 引用,將只被單一 group 使用的 schema 移到該 group 的 types.ts
|
|
1565
|
+
*/
|
|
1566
|
+
splitSchemaByUsage() {
|
|
1567
|
+
if (!this.openApiDoc || this.groupOperationDefs.size === 0) return;
|
|
1568
|
+
const rawSchemas = this.openApiDoc.components?.schemas ?? {};
|
|
1569
|
+
const allSchemaNames = Object.keys(this.schemaInterfaces);
|
|
1570
|
+
const analysis = analyzeSchemaRefs(
|
|
1571
|
+
this.groupOperationDefs,
|
|
1572
|
+
rawSchemas,
|
|
1573
|
+
allSchemaNames
|
|
1574
|
+
);
|
|
1575
|
+
this.sharedSchemaNames = analysis.sharedSchemas;
|
|
1576
|
+
for (const group of this.generatedContent.groups) {
|
|
1577
|
+
const localNames = analysis.groupLocalSchemas.get(group.groupKey);
|
|
1578
|
+
if (!localNames || localNames.size === 0) continue;
|
|
1579
|
+
const groupOptions = this.groupGenerationOptions.get(group.groupKey);
|
|
1580
|
+
if (!groupOptions || !this.parserService) continue;
|
|
1581
|
+
const localSchemaInterfaces = {};
|
|
1582
|
+
for (const name of localNames) {
|
|
1583
|
+
if (this.schemaInterfaces[name]) {
|
|
1584
|
+
localSchemaInterfaces[name] = this.schemaInterfaces[name];
|
|
1585
|
+
}
|
|
1586
|
+
}
|
|
1587
|
+
const infoExtractor = new EndpointInfoExtractor(groupOptions);
|
|
1588
|
+
const operationDefs = this.groupOperationDefs.get(group.groupKey) ?? [];
|
|
1589
|
+
const endpointInfos = infoExtractor.extractEndpointInfos(operationDefs);
|
|
1590
|
+
const generatorOptions = {
|
|
1591
|
+
...groupOptions,
|
|
1592
|
+
apiConfiguration: groupOptions.apiConfiguration || {
|
|
1593
|
+
file: "@/store/webapi",
|
|
1594
|
+
importName: "WebApiConfiguration"
|
|
1595
|
+
}
|
|
1596
|
+
};
|
|
1597
|
+
const newTypesContent = generateTypesFile(
|
|
1598
|
+
endpointInfos,
|
|
1599
|
+
generatorOptions,
|
|
1600
|
+
this.schemaInterfaces,
|
|
1601
|
+
operationDefs,
|
|
1602
|
+
{
|
|
1603
|
+
localSchemaInterfaces,
|
|
1604
|
+
localSchemaNames: localNames
|
|
1605
|
+
}
|
|
1606
|
+
);
|
|
1607
|
+
group.content.files.types = newTypesContent;
|
|
1608
|
+
}
|
|
1609
|
+
}
|
|
1610
|
+
// 儲存 shared schema 名稱(只有這些會寫入 schema.ts)
|
|
1611
|
+
sharedSchemaNames = null;
|
|
1301
1612
|
/**
|
|
1302
1613
|
* 生成 common types
|
|
1303
1614
|
*/
|
|
@@ -1305,10 +1616,13 @@ var UnifiedCodeGenerator = class {
|
|
|
1305
1616
|
this.generatedContent.commonTypes = generateCommonTypesFile();
|
|
1306
1617
|
}
|
|
1307
1618
|
/**
|
|
1308
|
-
* 生成Schema
|
|
1619
|
+
* 生成Schema(只包含 shared types,排除 group-local 和未使用的 types)
|
|
1309
1620
|
*/
|
|
1310
1621
|
async generateSchemaContent() {
|
|
1311
|
-
this.generatedContent.componentSchema = generateComponentSchemaFile(
|
|
1622
|
+
this.generatedContent.componentSchema = generateComponentSchemaFile(
|
|
1623
|
+
this.schemaInterfaces,
|
|
1624
|
+
this.sharedSchemaNames ?? void 0
|
|
1625
|
+
);
|
|
1312
1626
|
}
|
|
1313
1627
|
/**
|
|
1314
1628
|
* 生成 DO_NOT_MODIFY.md
|
|
@@ -1416,6 +1730,9 @@ var UnifiedCodeGenerator = class {
|
|
|
1416
1730
|
if (!this.openApiDoc || !this.parserService) {
|
|
1417
1731
|
throw new Error("OpenAPI \u6587\u6A94\u672A\u521D\u59CB\u5316\uFF0C\u8ACB\u5148\u8ABF\u7528 prepare()");
|
|
1418
1732
|
}
|
|
1733
|
+
const groupOpDefs = this.parserService.getOperationDefinitions(groupOptions.filterEndpoints);
|
|
1734
|
+
this.groupOperationDefs.set(groupInfo.groupKey, groupOpDefs);
|
|
1735
|
+
this.groupGenerationOptions.set(groupInfo.groupKey, groupOptions);
|
|
1419
1736
|
const apiGenerator = new ApiCodeGenerator(this.parserService, groupOptions);
|
|
1420
1737
|
const result = await apiGenerator.generate();
|
|
1421
1738
|
return result;
|
|
@@ -1424,11 +1741,12 @@ var UnifiedCodeGenerator = class {
|
|
|
1424
1741
|
* 生成主 index.ts 檔案
|
|
1425
1742
|
*/
|
|
1426
1743
|
generateMainIndex(generatedGroups) {
|
|
1427
|
-
const
|
|
1744
|
+
const groupExports = generatedGroups.map((groupKey) => `export * from "./${groupKey}";`).join("\n");
|
|
1428
1745
|
return `/* eslint-disable */
|
|
1429
1746
|
// [Warning] Generated automatically - do not edit manually
|
|
1430
1747
|
|
|
1431
|
-
|
|
1748
|
+
export * from "./schema";
|
|
1749
|
+
${groupExports}
|
|
1432
1750
|
`;
|
|
1433
1751
|
}
|
|
1434
1752
|
};
|