@acrool/rtk-query-codegen-openapi 1.3.0-alpha.1 → 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
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,7 @@ function renameIdentifier(node, oldName, newName) {
|
|
|
514
514
|
})
|
|
515
515
|
]).transformed[0];
|
|
516
516
|
}
|
|
517
|
-
function generateComponentSchemaFile(interfaces) {
|
|
517
|
+
function generateComponentSchemaFile(interfaces, includeOnly) {
|
|
518
518
|
const printer = import_typescript.default.createPrinter({ newLine: import_typescript.default.NewLineKind.LineFeed });
|
|
519
519
|
const resultFile = import_typescript.default.createSourceFile(
|
|
520
520
|
"component-schema.ts",
|
|
@@ -528,6 +528,9 @@ function generateComponentSchemaFile(interfaces) {
|
|
|
528
528
|
Object.entries(interfaces).forEach(([originalName, node]) => {
|
|
529
529
|
const pascalCaseName = toPascalCase(originalName);
|
|
530
530
|
typeNameMapping[originalName] = pascalCaseName;
|
|
531
|
+
if (includeOnly && !includeOnly.has(originalName)) {
|
|
532
|
+
return;
|
|
533
|
+
}
|
|
531
534
|
const renamedNode = renameIdentifier(node, originalName, pascalCaseName);
|
|
532
535
|
const printed = printer.printNode(import_typescript.default.EmitHint.Unspecified, renamedNode, resultFile);
|
|
533
536
|
renamedInterfaces.push(printed);
|
|
@@ -566,7 +569,7 @@ function generateDoNotModifyFile() {
|
|
|
566
569
|
|
|
567
570
|
// src/services/api-code-generator.ts
|
|
568
571
|
init_cjs_shims();
|
|
569
|
-
var
|
|
572
|
+
var import_typescript3 = __toESM(require("typescript"));
|
|
570
573
|
|
|
571
574
|
// src/services/endpoint-info-extractor.ts
|
|
572
575
|
init_cjs_shims();
|
|
@@ -668,10 +671,46 @@ var EndpointInfoExtractor = class {
|
|
|
668
671
|
|
|
669
672
|
// src/generators/types-generator.ts
|
|
670
673
|
init_cjs_shims();
|
|
674
|
+
var import_typescript2 = __toESM(require("typescript"));
|
|
671
675
|
var toPascalCase2 = (name) => {
|
|
672
676
|
return name.charAt(0).toUpperCase() + name.slice(1);
|
|
673
677
|
};
|
|
674
|
-
function
|
|
678
|
+
function renameIdentifier2(node, oldName, newName) {
|
|
679
|
+
return import_typescript2.default.transform(node, [
|
|
680
|
+
(context) => (rootNode) => import_typescript2.default.visitNode(rootNode, function visit(node2) {
|
|
681
|
+
if (import_typescript2.default.isIdentifier(node2) && node2.text === oldName) {
|
|
682
|
+
return import_typescript2.default.factory.createIdentifier(newName);
|
|
683
|
+
}
|
|
684
|
+
return import_typescript2.default.visitEachChild(node2, visit, context);
|
|
685
|
+
})
|
|
686
|
+
]).transformed[0];
|
|
687
|
+
}
|
|
688
|
+
function prefixSharedSchemaRefs(node, allSchemaNames, localSchemaNames, declarationName) {
|
|
689
|
+
const sharedNames = /* @__PURE__ */ new Set();
|
|
690
|
+
for (const name of allSchemaNames) {
|
|
691
|
+
if (!localSchemaNames.has(name)) {
|
|
692
|
+
sharedNames.add(toPascalCase2(name));
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
return import_typescript2.default.transform(node, [
|
|
696
|
+
(context) => (rootNode) => import_typescript2.default.visitNode(rootNode, function visit(node2) {
|
|
697
|
+
if (import_typescript2.default.isTypeReferenceNode(node2) && import_typescript2.default.isIdentifier(node2.typeName)) {
|
|
698
|
+
const name = node2.typeName.text;
|
|
699
|
+
if (sharedNames.has(name) && name !== declarationName) {
|
|
700
|
+
const qualifiedName = import_typescript2.default.factory.createQualifiedName(
|
|
701
|
+
import_typescript2.default.factory.createIdentifier("Schema"),
|
|
702
|
+
import_typescript2.default.factory.createIdentifier(name)
|
|
703
|
+
);
|
|
704
|
+
return import_typescript2.default.factory.createTypeReferenceNode(qualifiedName, node2.typeArguments);
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
return import_typescript2.default.visitEachChild(node2, visit, context);
|
|
708
|
+
})
|
|
709
|
+
]).transformed[0];
|
|
710
|
+
}
|
|
711
|
+
function generateTypesFile(endpointInfos, _options, schemaInterfaces, operationDefinitions, localSchemaOptions) {
|
|
712
|
+
const localSchemaNames = localSchemaOptions?.localSchemaNames ?? /* @__PURE__ */ new Set();
|
|
713
|
+
const localSchemaInterfaces = localSchemaOptions?.localSchemaInterfaces ?? {};
|
|
675
714
|
const schemaTypeMap = {};
|
|
676
715
|
if (schemaInterfaces) {
|
|
677
716
|
Object.keys(schemaInterfaces).forEach((actualTypeName) => {
|
|
@@ -686,23 +725,41 @@ function generateTypesFile(endpointInfos, _options, schemaInterfaces, operationD
|
|
|
686
725
|
}
|
|
687
726
|
});
|
|
688
727
|
}
|
|
728
|
+
const hasSharedSchemaTypes = schemaInterfaces && Object.keys(schemaInterfaces).some(
|
|
729
|
+
(name) => !localSchemaNames.has(name)
|
|
730
|
+
);
|
|
689
731
|
let importStatement = `/* eslint-disable */
|
|
690
|
-
// [Warning] Generated automatically - do not edit manually
|
|
691
|
-
|
|
732
|
+
// [Warning] Generated automatically - do not edit manually
|
|
733
|
+
|
|
692
734
|
`;
|
|
693
|
-
|
|
694
|
-
if (hasSchemaTypes) {
|
|
735
|
+
if (hasSharedSchemaTypes) {
|
|
695
736
|
importStatement += `import * as Schema from "../schema";
|
|
696
737
|
`;
|
|
697
738
|
}
|
|
698
739
|
importStatement += "\n";
|
|
699
740
|
const typeDefinitions = [];
|
|
741
|
+
if (Object.keys(localSchemaInterfaces).length > 0) {
|
|
742
|
+
const printer = import_typescript2.default.createPrinter({ newLine: import_typescript2.default.NewLineKind.LineFeed });
|
|
743
|
+
const resultFile = import_typescript2.default.createSourceFile("types.ts", "", import_typescript2.default.ScriptTarget.Latest, false, import_typescript2.default.ScriptKind.TS);
|
|
744
|
+
const localTypeDefs = [];
|
|
745
|
+
const allSchemaNameSet = new Set(schemaInterfaces ? Object.keys(schemaInterfaces) : []);
|
|
746
|
+
for (const [originalName, node] of Object.entries(localSchemaInterfaces)) {
|
|
747
|
+
const pascalCaseName = toPascalCase2(originalName);
|
|
748
|
+
let transformedNode = renameIdentifier2(node, originalName, pascalCaseName);
|
|
749
|
+
transformedNode = prefixSharedSchemaRefs(transformedNode, allSchemaNameSet, localSchemaNames, pascalCaseName);
|
|
750
|
+
const printed = printer.printNode(import_typescript2.default.EmitHint.Unspecified, transformedNode, resultFile);
|
|
751
|
+
localTypeDefs.push(printed);
|
|
752
|
+
}
|
|
753
|
+
if (localTypeDefs.length > 0) {
|
|
754
|
+
typeDefinitions.push(localTypeDefs.join("\n"));
|
|
755
|
+
}
|
|
756
|
+
}
|
|
700
757
|
const endpointTypes = [];
|
|
701
758
|
endpointInfos.forEach((endpoint) => {
|
|
702
759
|
const reqTypeName = endpoint.argTypeName;
|
|
703
760
|
const resTypeName = endpoint.responseTypeName;
|
|
704
761
|
if (reqTypeName) {
|
|
705
|
-
const requestTypeContent = generateRequestTypeContent(endpoint, operationDefinitions, schemaTypeMap);
|
|
762
|
+
const requestTypeContent = generateRequestTypeContent(endpoint, operationDefinitions, schemaTypeMap, localSchemaNames);
|
|
706
763
|
if (requestTypeContent.trim() === "") {
|
|
707
764
|
endpointTypes.push(
|
|
708
765
|
`export type ${reqTypeName} = void;`,
|
|
@@ -718,7 +775,7 @@ function generateTypesFile(endpointInfos, _options, schemaInterfaces, operationD
|
|
|
718
775
|
}
|
|
719
776
|
}
|
|
720
777
|
if (resTypeName) {
|
|
721
|
-
const responseTypeResult = generateResponseTypeContent(endpoint, operationDefinitions, schemaTypeMap);
|
|
778
|
+
const responseTypeResult = generateResponseTypeContent(endpoint, operationDefinitions, schemaTypeMap, localSchemaNames);
|
|
722
779
|
if (responseTypeResult.content.trim() === "") {
|
|
723
780
|
endpointTypes.push(
|
|
724
781
|
`export type ${resTypeName} = void;`,
|
|
@@ -751,19 +808,19 @@ function generateTypesFile(endpointInfos, _options, schemaInterfaces, operationD
|
|
|
751
808
|
}
|
|
752
809
|
return importStatement + typeDefinitions.join("\n\n");
|
|
753
810
|
}
|
|
754
|
-
function generateRequestTypeContent(endpoint, operationDefinitions, schemaTypeMap = {}) {
|
|
811
|
+
function generateRequestTypeContent(endpoint, operationDefinitions, schemaTypeMap = {}, localSchemaNames = /* @__PURE__ */ new Set()) {
|
|
755
812
|
const properties = [];
|
|
756
813
|
if (endpoint.queryParams && endpoint.queryParams.length > 0) {
|
|
757
814
|
endpoint.queryParams.forEach((param) => {
|
|
758
815
|
const optional = param.required ? "" : "?";
|
|
759
|
-
const paramType = getTypeFromParameter(param, schemaTypeMap);
|
|
816
|
+
const paramType = getTypeFromParameter(param, schemaTypeMap, localSchemaNames);
|
|
760
817
|
properties.push(` ${param.name}${optional}: ${paramType};`);
|
|
761
818
|
});
|
|
762
819
|
}
|
|
763
820
|
if (endpoint.pathParams && endpoint.pathParams.length > 0) {
|
|
764
821
|
endpoint.pathParams.forEach((param) => {
|
|
765
822
|
const optional = param.required ? "" : "?";
|
|
766
|
-
const paramType = getTypeFromParameter(param, schemaTypeMap);
|
|
823
|
+
const paramType = getTypeFromParameter(param, schemaTypeMap, localSchemaNames);
|
|
767
824
|
properties.push(` ${param.name}${optional}: ${paramType};`);
|
|
768
825
|
});
|
|
769
826
|
}
|
|
@@ -777,15 +834,15 @@ function generateRequestTypeContent(endpoint, operationDefinitions, schemaTypeMa
|
|
|
777
834
|
const jsonContent = content["application/json"] || content["*/*"];
|
|
778
835
|
const formContent = content["multipart/form-data"] || content["application/x-www-form-urlencoded"];
|
|
779
836
|
if (jsonContent?.schema) {
|
|
780
|
-
const bodyType = getTypeFromSchema(jsonContent.schema, schemaTypeMap, 1);
|
|
837
|
+
const bodyType = getTypeFromSchema(jsonContent.schema, schemaTypeMap, 1, localSchemaNames);
|
|
781
838
|
properties.push(` body: ${bodyType};`);
|
|
782
839
|
} else if (formContent?.schema) {
|
|
783
|
-
const bodyType = getTypeFromSchema(formContent.schema, schemaTypeMap, 1);
|
|
840
|
+
const bodyType = getTypeFromSchema(formContent.schema, schemaTypeMap, 1, localSchemaNames);
|
|
784
841
|
properties.push(` body: ${bodyType};`);
|
|
785
842
|
} else {
|
|
786
843
|
const firstContent = Object.values(content)[0];
|
|
787
844
|
if (firstContent?.schema) {
|
|
788
|
-
const bodyType = getTypeFromSchema(firstContent.schema, schemaTypeMap, 1);
|
|
845
|
+
const bodyType = getTypeFromSchema(firstContent.schema, schemaTypeMap, 1, localSchemaNames);
|
|
789
846
|
properties.push(` body: ${bodyType};`);
|
|
790
847
|
} else {
|
|
791
848
|
properties.push(` body?: any; // Request body from OpenAPI`);
|
|
@@ -797,7 +854,7 @@ function generateRequestTypeContent(endpoint, operationDefinitions, schemaTypeMa
|
|
|
797
854
|
}
|
|
798
855
|
return properties.join("\n");
|
|
799
856
|
}
|
|
800
|
-
function generateResponseTypeContent(endpoint, operationDefinitions, schemaTypeMap = {}) {
|
|
857
|
+
function generateResponseTypeContent(endpoint, operationDefinitions, schemaTypeMap = {}, localSchemaNames = /* @__PURE__ */ new Set()) {
|
|
801
858
|
const operationDef = operationDefinitions?.find((op) => {
|
|
802
859
|
return op.operation?.operationId === endpoint.operationName || op.operation?.operationId === endpoint.operationName.toLowerCase() || // 也嘗試匹配 verb + path 組合
|
|
803
860
|
op.verb === endpoint.verb.toLowerCase() && op.path === endpoint.path;
|
|
@@ -809,12 +866,12 @@ function generateResponseTypeContent(endpoint, operationDefinitions, schemaTypeM
|
|
|
809
866
|
if (jsonContent?.schema) {
|
|
810
867
|
const schema = jsonContent.schema;
|
|
811
868
|
if (schema.$ref || schema.type !== "object" || !schema.properties) {
|
|
812
|
-
const directType = getTypeFromSchema(schema, schemaTypeMap, 0);
|
|
869
|
+
const directType = getTypeFromSchema(schema, schemaTypeMap, 0, localSchemaNames);
|
|
813
870
|
if (directType && directType !== "any") {
|
|
814
871
|
return { content: directType, isDirectType: true };
|
|
815
872
|
}
|
|
816
873
|
}
|
|
817
|
-
const responseProps = parseSchemaProperties(schema, schemaTypeMap);
|
|
874
|
+
const responseProps = parseSchemaProperties(schema, schemaTypeMap, localSchemaNames);
|
|
818
875
|
if (responseProps.length > 0) {
|
|
819
876
|
return { content: responseProps.join("\n"), isDirectType: false };
|
|
820
877
|
}
|
|
@@ -823,14 +880,14 @@ function generateResponseTypeContent(endpoint, operationDefinitions, schemaTypeM
|
|
|
823
880
|
}
|
|
824
881
|
return { content: "", isDirectType: false };
|
|
825
882
|
}
|
|
826
|
-
function parseSchemaProperties(schema, schemaTypeMap = {}) {
|
|
883
|
+
function parseSchemaProperties(schema, schemaTypeMap = {}, localSchemaNames = /* @__PURE__ */ new Set()) {
|
|
827
884
|
const properties = [];
|
|
828
885
|
if (schema.type === "object" && schema.properties) {
|
|
829
886
|
const required = schema.required || [];
|
|
830
887
|
Object.entries(schema.properties).forEach(([propName, propSchema]) => {
|
|
831
888
|
const isRequired = required.includes(propName);
|
|
832
889
|
const optional = isRequired ? "" : "?";
|
|
833
|
-
const propType = getTypeFromSchema(propSchema, schemaTypeMap, 1);
|
|
890
|
+
const propType = getTypeFromSchema(propSchema, schemaTypeMap, 1, localSchemaNames);
|
|
834
891
|
const needsQuotes = /[^a-zA-Z0-9_$]/.test(propName);
|
|
835
892
|
const quotedPropName = needsQuotes ? `"${propName}"` : propName;
|
|
836
893
|
if (propSchema.description) {
|
|
@@ -841,7 +898,7 @@ function parseSchemaProperties(schema, schemaTypeMap = {}) {
|
|
|
841
898
|
}
|
|
842
899
|
return properties;
|
|
843
900
|
}
|
|
844
|
-
function getTypeFromSchema(schema, schemaTypeMap = {}, indentLevel = 0) {
|
|
901
|
+
function getTypeFromSchema(schema, schemaTypeMap = {}, indentLevel = 0, localSchemaNames = /* @__PURE__ */ new Set()) {
|
|
845
902
|
if (!schema) return "any";
|
|
846
903
|
if (schema.$ref) {
|
|
847
904
|
const refPath = schema.$ref;
|
|
@@ -849,7 +906,7 @@ function getTypeFromSchema(schema, schemaTypeMap = {}, indentLevel = 0) {
|
|
|
849
906
|
const originalTypeName = refPath.replace("#/components/schemas/", "");
|
|
850
907
|
const actualTypeName = schemaTypeMap[originalTypeName] || originalTypeName;
|
|
851
908
|
const pascalCaseTypeName = toPascalCase2(actualTypeName);
|
|
852
|
-
const baseType2 = `Schema.${pascalCaseTypeName}`;
|
|
909
|
+
const baseType2 = localSchemaNames.has(originalTypeName) ? pascalCaseTypeName : `Schema.${pascalCaseTypeName}`;
|
|
853
910
|
return schema.nullable ? `${baseType2} | null` : baseType2;
|
|
854
911
|
}
|
|
855
912
|
}
|
|
@@ -872,7 +929,7 @@ function getTypeFromSchema(schema, schemaTypeMap = {}, indentLevel = 0) {
|
|
|
872
929
|
baseType = "boolean";
|
|
873
930
|
break;
|
|
874
931
|
case "array":
|
|
875
|
-
const itemType = schema.items ? getTypeFromSchema(schema.items, schemaTypeMap, indentLevel) : "any";
|
|
932
|
+
const itemType = schema.items ? getTypeFromSchema(schema.items, schemaTypeMap, indentLevel, localSchemaNames) : "any";
|
|
876
933
|
const needsParentheses = itemType.includes("|");
|
|
877
934
|
baseType = needsParentheses ? `(${itemType})[]` : `${itemType}[]`;
|
|
878
935
|
break;
|
|
@@ -881,7 +938,7 @@ function getTypeFromSchema(schema, schemaTypeMap = {}, indentLevel = 0) {
|
|
|
881
938
|
const entries = Object.entries(schema.properties);
|
|
882
939
|
if (entries.length === 0) {
|
|
883
940
|
if (schema.additionalProperties) {
|
|
884
|
-
const valueType = schema.additionalProperties === true ? "any" : getTypeFromSchema(schema.additionalProperties, schemaTypeMap, indentLevel);
|
|
941
|
+
const valueType = schema.additionalProperties === true ? "any" : getTypeFromSchema(schema.additionalProperties, schemaTypeMap, indentLevel, localSchemaNames);
|
|
885
942
|
baseType = `Record<string, ${valueType}>`;
|
|
886
943
|
} else {
|
|
887
944
|
baseType = "{}";
|
|
@@ -893,7 +950,7 @@ function getTypeFromSchema(schema, schemaTypeMap = {}, indentLevel = 0) {
|
|
|
893
950
|
entries.forEach(([key, propSchema]) => {
|
|
894
951
|
const required = schema.required || [];
|
|
895
952
|
const optional = required.includes(key) ? "" : "?";
|
|
896
|
-
const type = getTypeFromSchema(propSchema, schemaTypeMap, indentLevel + 1);
|
|
953
|
+
const type = getTypeFromSchema(propSchema, schemaTypeMap, indentLevel + 1, localSchemaNames);
|
|
897
954
|
const needsQuotes = /[^a-zA-Z0-9_$]/.test(key);
|
|
898
955
|
const quotedKey = needsQuotes ? `"${key}"` : key;
|
|
899
956
|
if (propSchema.description) {
|
|
@@ -906,7 +963,7 @@ ${props.join("\n")}
|
|
|
906
963
|
${currentIndent}}`;
|
|
907
964
|
}
|
|
908
965
|
} else if (schema.additionalProperties) {
|
|
909
|
-
const valueType = schema.additionalProperties === true ? "any" : getTypeFromSchema(schema.additionalProperties, schemaTypeMap, indentLevel);
|
|
966
|
+
const valueType = schema.additionalProperties === true ? "any" : getTypeFromSchema(schema.additionalProperties, schemaTypeMap, indentLevel, localSchemaNames);
|
|
910
967
|
baseType = `Record<string, ${valueType}>`;
|
|
911
968
|
} else {
|
|
912
969
|
baseType = "any";
|
|
@@ -918,9 +975,9 @@ ${currentIndent}}`;
|
|
|
918
975
|
}
|
|
919
976
|
return schema.nullable ? `${baseType} | null` : baseType;
|
|
920
977
|
}
|
|
921
|
-
function getTypeFromParameter(param, schemaTypeMap = {}) {
|
|
978
|
+
function getTypeFromParameter(param, schemaTypeMap = {}, localSchemaNames = /* @__PURE__ */ new Set()) {
|
|
922
979
|
if (!param.schema) return "any";
|
|
923
|
-
return getTypeFromSchema(param.schema, schemaTypeMap);
|
|
980
|
+
return getTypeFromSchema(param.schema, schemaTypeMap, 0, localSchemaNames);
|
|
924
981
|
}
|
|
925
982
|
|
|
926
983
|
// src/generators/rtk-query-generator.ts
|
|
@@ -1117,7 +1174,7 @@ var ApiCodeGenerator = class {
|
|
|
1117
1174
|
};
|
|
1118
1175
|
const apiGen = this.parserService.getApiGenerator();
|
|
1119
1176
|
const schemaInterfaces = apiGen.aliases.reduce((curr, alias) => {
|
|
1120
|
-
if (
|
|
1177
|
+
if (import_typescript3.default.isInterfaceDeclaration(alias) || import_typescript3.default.isTypeAliasDeclaration(alias)) {
|
|
1121
1178
|
const name = alias.name.text;
|
|
1122
1179
|
return {
|
|
1123
1180
|
...curr,
|
|
@@ -1201,6 +1258,150 @@ ${enumEntries}
|
|
|
1201
1258
|
`;
|
|
1202
1259
|
}
|
|
1203
1260
|
|
|
1261
|
+
// src/utils/schema-ref-analyzer.ts
|
|
1262
|
+
init_cjs_shims();
|
|
1263
|
+
function collectRefsFromSchema(schema, refs) {
|
|
1264
|
+
if (!schema || typeof schema !== "object") return;
|
|
1265
|
+
if (schema.$ref && typeof schema.$ref === "string") {
|
|
1266
|
+
const match = schema.$ref.match(/^#\/components\/schemas\/(.+)$/);
|
|
1267
|
+
if (match) {
|
|
1268
|
+
refs.add(match[1]);
|
|
1269
|
+
}
|
|
1270
|
+
}
|
|
1271
|
+
if (schema.properties) {
|
|
1272
|
+
for (const prop of Object.values(schema.properties)) {
|
|
1273
|
+
collectRefsFromSchema(prop, refs);
|
|
1274
|
+
}
|
|
1275
|
+
}
|
|
1276
|
+
if (schema.items) {
|
|
1277
|
+
collectRefsFromSchema(schema.items, refs);
|
|
1278
|
+
}
|
|
1279
|
+
if (schema.additionalProperties && typeof schema.additionalProperties === "object") {
|
|
1280
|
+
collectRefsFromSchema(schema.additionalProperties, refs);
|
|
1281
|
+
}
|
|
1282
|
+
for (const key of ["allOf", "oneOf", "anyOf"]) {
|
|
1283
|
+
if (Array.isArray(schema[key])) {
|
|
1284
|
+
for (const item of schema[key]) {
|
|
1285
|
+
collectRefsFromSchema(item, refs);
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
}
|
|
1289
|
+
}
|
|
1290
|
+
function collectDirectRefs(operationDefs) {
|
|
1291
|
+
const refs = /* @__PURE__ */ new Set();
|
|
1292
|
+
for (const opDef of operationDefs) {
|
|
1293
|
+
const op = opDef.operation;
|
|
1294
|
+
if (op.parameters) {
|
|
1295
|
+
for (const param of op.parameters) {
|
|
1296
|
+
const p = param;
|
|
1297
|
+
if (p.schema) {
|
|
1298
|
+
collectRefsFromSchema(p.schema, refs);
|
|
1299
|
+
}
|
|
1300
|
+
}
|
|
1301
|
+
}
|
|
1302
|
+
if (op.requestBody) {
|
|
1303
|
+
const rb = op.requestBody;
|
|
1304
|
+
if (rb.content) {
|
|
1305
|
+
for (const ct of Object.values(rb.content)) {
|
|
1306
|
+
if (ct.schema) {
|
|
1307
|
+
collectRefsFromSchema(ct.schema, refs);
|
|
1308
|
+
}
|
|
1309
|
+
}
|
|
1310
|
+
}
|
|
1311
|
+
}
|
|
1312
|
+
if (op.responses) {
|
|
1313
|
+
for (const resp of Object.values(op.responses)) {
|
|
1314
|
+
const r = resp;
|
|
1315
|
+
if (r.content) {
|
|
1316
|
+
for (const ct of Object.values(r.content)) {
|
|
1317
|
+
if (ct.schema) {
|
|
1318
|
+
collectRefsFromSchema(ct.schema, refs);
|
|
1319
|
+
}
|
|
1320
|
+
}
|
|
1321
|
+
}
|
|
1322
|
+
}
|
|
1323
|
+
}
|
|
1324
|
+
}
|
|
1325
|
+
return refs;
|
|
1326
|
+
}
|
|
1327
|
+
function resolveTransitiveDeps(directRefs, allSchemas) {
|
|
1328
|
+
const resolved = /* @__PURE__ */ new Set();
|
|
1329
|
+
const queue = [...directRefs];
|
|
1330
|
+
while (queue.length > 0) {
|
|
1331
|
+
const name = queue.pop();
|
|
1332
|
+
if (resolved.has(name)) continue;
|
|
1333
|
+
resolved.add(name);
|
|
1334
|
+
const schema = allSchemas[name];
|
|
1335
|
+
if (!schema) continue;
|
|
1336
|
+
const nestedRefs = /* @__PURE__ */ new Set();
|
|
1337
|
+
collectRefsFromSchema(schema, nestedRefs);
|
|
1338
|
+
for (const ref of nestedRefs) {
|
|
1339
|
+
if (!resolved.has(ref)) {
|
|
1340
|
+
queue.push(ref);
|
|
1341
|
+
}
|
|
1342
|
+
}
|
|
1343
|
+
}
|
|
1344
|
+
return resolved;
|
|
1345
|
+
}
|
|
1346
|
+
function analyzeSchemaRefs(groupOperations, allSchemas, allSchemaNames) {
|
|
1347
|
+
const groupRefs = /* @__PURE__ */ new Map();
|
|
1348
|
+
for (const [groupKey, opDefs] of groupOperations) {
|
|
1349
|
+
const directRefs = collectDirectRefs(opDefs);
|
|
1350
|
+
const fullRefs = resolveTransitiveDeps(directRefs, allSchemas);
|
|
1351
|
+
groupRefs.set(groupKey, fullRefs);
|
|
1352
|
+
}
|
|
1353
|
+
const refCountMap = /* @__PURE__ */ new Map();
|
|
1354
|
+
for (const [groupKey, refs] of groupRefs) {
|
|
1355
|
+
for (const schemaName of refs) {
|
|
1356
|
+
if (!refCountMap.has(schemaName)) {
|
|
1357
|
+
refCountMap.set(schemaName, /* @__PURE__ */ new Set());
|
|
1358
|
+
}
|
|
1359
|
+
refCountMap.get(schemaName).add(groupKey);
|
|
1360
|
+
}
|
|
1361
|
+
}
|
|
1362
|
+
const sharedSchemas = /* @__PURE__ */ new Set();
|
|
1363
|
+
const groupLocalSchemas = /* @__PURE__ */ new Map();
|
|
1364
|
+
const unusedSchemas = /* @__PURE__ */ new Set();
|
|
1365
|
+
for (const schemaName of allSchemaNames) {
|
|
1366
|
+
const groups = refCountMap.get(schemaName);
|
|
1367
|
+
if (!groups || groups.size === 0) {
|
|
1368
|
+
unusedSchemas.add(schemaName);
|
|
1369
|
+
} else if (groups.size === 1) {
|
|
1370
|
+
const groupKey = [...groups][0];
|
|
1371
|
+
if (!groupLocalSchemas.has(groupKey)) {
|
|
1372
|
+
groupLocalSchemas.set(groupKey, /* @__PURE__ */ new Set());
|
|
1373
|
+
}
|
|
1374
|
+
groupLocalSchemas.get(groupKey).add(schemaName);
|
|
1375
|
+
} else {
|
|
1376
|
+
sharedSchemas.add(schemaName);
|
|
1377
|
+
}
|
|
1378
|
+
}
|
|
1379
|
+
let changed = true;
|
|
1380
|
+
while (changed) {
|
|
1381
|
+
changed = false;
|
|
1382
|
+
for (const [groupKey, localSchemas] of groupLocalSchemas) {
|
|
1383
|
+
for (const schemaName of [...localSchemas]) {
|
|
1384
|
+
const schema = allSchemas[schemaName];
|
|
1385
|
+
if (!schema) continue;
|
|
1386
|
+
const deps = /* @__PURE__ */ new Set();
|
|
1387
|
+
collectRefsFromSchema(schema, deps);
|
|
1388
|
+
for (const dep of deps) {
|
|
1389
|
+
for (const [otherGroup, otherLocals] of groupLocalSchemas) {
|
|
1390
|
+
if (otherGroup !== groupKey && otherLocals.has(dep)) {
|
|
1391
|
+
sharedSchemas.add(dep);
|
|
1392
|
+
sharedSchemas.add(schemaName);
|
|
1393
|
+
otherLocals.delete(dep);
|
|
1394
|
+
localSchemas.delete(schemaName);
|
|
1395
|
+
changed = true;
|
|
1396
|
+
}
|
|
1397
|
+
}
|
|
1398
|
+
}
|
|
1399
|
+
}
|
|
1400
|
+
}
|
|
1401
|
+
}
|
|
1402
|
+
return { sharedSchemas, groupLocalSchemas, unusedSchemas };
|
|
1403
|
+
}
|
|
1404
|
+
|
|
1204
1405
|
// src/services/unified-code-generator.ts
|
|
1205
1406
|
var UnifiedCodeGenerator = class {
|
|
1206
1407
|
_options;
|
|
@@ -1223,6 +1424,10 @@ var UnifiedCodeGenerator = class {
|
|
|
1223
1424
|
};
|
|
1224
1425
|
// 收集所有 tags
|
|
1225
1426
|
allTags = /* @__PURE__ */ new Set();
|
|
1427
|
+
// 收集每個 group 的 operation definitions(用於 schema 引用分析)
|
|
1428
|
+
groupOperationDefs = /* @__PURE__ */ new Map();
|
|
1429
|
+
// 收集每個 group 的生成選項(用於重新生成 types)
|
|
1430
|
+
groupGenerationOptions = /* @__PURE__ */ new Map();
|
|
1226
1431
|
constructor(options) {
|
|
1227
1432
|
this._options = options;
|
|
1228
1433
|
}
|
|
@@ -1232,6 +1437,7 @@ var UnifiedCodeGenerator = class {
|
|
|
1232
1437
|
async generateAll() {
|
|
1233
1438
|
await this.prepare();
|
|
1234
1439
|
await this.generateApi();
|
|
1440
|
+
this.splitSchemaByUsage();
|
|
1235
1441
|
this.generateCommonTypesContent();
|
|
1236
1442
|
this.generateSchemaContent();
|
|
1237
1443
|
this.generateUtilsContent();
|
|
@@ -1258,7 +1464,7 @@ var UnifiedCodeGenerator = class {
|
|
|
1258
1464
|
this.parserService.initialize();
|
|
1259
1465
|
const apiGen = this.parserService.getApiGenerator();
|
|
1260
1466
|
this.schemaInterfaces = apiGen.aliases.reduce((curr, alias) => {
|
|
1261
|
-
if (
|
|
1467
|
+
if (import_typescript4.default.isInterfaceDeclaration(alias) || import_typescript4.default.isTypeAliasDeclaration(alias)) {
|
|
1262
1468
|
const name = alias.name.text;
|
|
1263
1469
|
return {
|
|
1264
1470
|
...curr,
|
|
@@ -1298,6 +1504,55 @@ var UnifiedCodeGenerator = class {
|
|
|
1298
1504
|
}
|
|
1299
1505
|
}
|
|
1300
1506
|
}
|
|
1507
|
+
/**
|
|
1508
|
+
* 分析 schema 引用,將只被單一 group 使用的 schema 移到該 group 的 types.ts
|
|
1509
|
+
*/
|
|
1510
|
+
splitSchemaByUsage() {
|
|
1511
|
+
if (!this.openApiDoc || this.groupOperationDefs.size === 0) return;
|
|
1512
|
+
const rawSchemas = this.openApiDoc.components?.schemas ?? {};
|
|
1513
|
+
const allSchemaNames = Object.keys(this.schemaInterfaces);
|
|
1514
|
+
const analysis = analyzeSchemaRefs(
|
|
1515
|
+
this.groupOperationDefs,
|
|
1516
|
+
rawSchemas,
|
|
1517
|
+
allSchemaNames
|
|
1518
|
+
);
|
|
1519
|
+
this.sharedSchemaNames = analysis.sharedSchemas;
|
|
1520
|
+
for (const group of this.generatedContent.groups) {
|
|
1521
|
+
const localNames = analysis.groupLocalSchemas.get(group.groupKey);
|
|
1522
|
+
if (!localNames || localNames.size === 0) continue;
|
|
1523
|
+
const groupOptions = this.groupGenerationOptions.get(group.groupKey);
|
|
1524
|
+
if (!groupOptions || !this.parserService) continue;
|
|
1525
|
+
const localSchemaInterfaces = {};
|
|
1526
|
+
for (const name of localNames) {
|
|
1527
|
+
if (this.schemaInterfaces[name]) {
|
|
1528
|
+
localSchemaInterfaces[name] = this.schemaInterfaces[name];
|
|
1529
|
+
}
|
|
1530
|
+
}
|
|
1531
|
+
const infoExtractor = new EndpointInfoExtractor(groupOptions);
|
|
1532
|
+
const operationDefs = this.groupOperationDefs.get(group.groupKey) ?? [];
|
|
1533
|
+
const endpointInfos = infoExtractor.extractEndpointInfos(operationDefs);
|
|
1534
|
+
const generatorOptions = {
|
|
1535
|
+
...groupOptions,
|
|
1536
|
+
apiConfiguration: groupOptions.apiConfiguration || {
|
|
1537
|
+
file: "@/store/webapi",
|
|
1538
|
+
importName: "WebApiConfiguration"
|
|
1539
|
+
}
|
|
1540
|
+
};
|
|
1541
|
+
const newTypesContent = generateTypesFile(
|
|
1542
|
+
endpointInfos,
|
|
1543
|
+
generatorOptions,
|
|
1544
|
+
this.schemaInterfaces,
|
|
1545
|
+
operationDefs,
|
|
1546
|
+
{
|
|
1547
|
+
localSchemaInterfaces,
|
|
1548
|
+
localSchemaNames: localNames
|
|
1549
|
+
}
|
|
1550
|
+
);
|
|
1551
|
+
group.content.files.types = newTypesContent;
|
|
1552
|
+
}
|
|
1553
|
+
}
|
|
1554
|
+
// 儲存 shared schema 名稱(只有這些會寫入 schema.ts)
|
|
1555
|
+
sharedSchemaNames = null;
|
|
1301
1556
|
/**
|
|
1302
1557
|
* 生成 common types
|
|
1303
1558
|
*/
|
|
@@ -1305,10 +1560,13 @@ var UnifiedCodeGenerator = class {
|
|
|
1305
1560
|
this.generatedContent.commonTypes = generateCommonTypesFile();
|
|
1306
1561
|
}
|
|
1307
1562
|
/**
|
|
1308
|
-
* 生成Schema
|
|
1563
|
+
* 生成Schema(只包含 shared types,排除 group-local 和未使用的 types)
|
|
1309
1564
|
*/
|
|
1310
1565
|
async generateSchemaContent() {
|
|
1311
|
-
this.generatedContent.componentSchema = generateComponentSchemaFile(
|
|
1566
|
+
this.generatedContent.componentSchema = generateComponentSchemaFile(
|
|
1567
|
+
this.schemaInterfaces,
|
|
1568
|
+
this.sharedSchemaNames ?? void 0
|
|
1569
|
+
);
|
|
1312
1570
|
}
|
|
1313
1571
|
/**
|
|
1314
1572
|
* 生成 DO_NOT_MODIFY.md
|
|
@@ -1416,6 +1674,9 @@ var UnifiedCodeGenerator = class {
|
|
|
1416
1674
|
if (!this.openApiDoc || !this.parserService) {
|
|
1417
1675
|
throw new Error("OpenAPI \u6587\u6A94\u672A\u521D\u59CB\u5316\uFF0C\u8ACB\u5148\u8ABF\u7528 prepare()");
|
|
1418
1676
|
}
|
|
1677
|
+
const groupOpDefs = this.parserService.getOperationDefinitions(groupOptions.filterEndpoints);
|
|
1678
|
+
this.groupOperationDefs.set(groupInfo.groupKey, groupOpDefs);
|
|
1679
|
+
this.groupGenerationOptions.set(groupInfo.groupKey, groupOptions);
|
|
1419
1680
|
const apiGenerator = new ApiCodeGenerator(this.parserService, groupOptions);
|
|
1420
1681
|
const result = await apiGenerator.generate();
|
|
1421
1682
|
return result;
|
|
@@ -1424,11 +1685,12 @@ var UnifiedCodeGenerator = class {
|
|
|
1424
1685
|
* 生成主 index.ts 檔案
|
|
1425
1686
|
*/
|
|
1426
1687
|
generateMainIndex(generatedGroups) {
|
|
1427
|
-
const
|
|
1688
|
+
const groupExports = generatedGroups.map((groupKey) => `export * from "./${groupKey}";`).join("\n");
|
|
1428
1689
|
return `/* eslint-disable */
|
|
1429
1690
|
// [Warning] Generated automatically - do not edit manually
|
|
1430
1691
|
|
|
1431
|
-
|
|
1692
|
+
export * from "./schema";
|
|
1693
|
+
${groupExports}
|
|
1432
1694
|
`;
|
|
1433
1695
|
}
|
|
1434
1696
|
};
|