@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.mjs
CHANGED
|
@@ -93,7 +93,7 @@ init_esm_shims();
|
|
|
93
93
|
// src/services/unified-code-generator.ts
|
|
94
94
|
init_esm_shims();
|
|
95
95
|
import path4 from "node:path";
|
|
96
|
-
import
|
|
96
|
+
import ts4 from "typescript";
|
|
97
97
|
|
|
98
98
|
// src/services/openapi-service.ts
|
|
99
99
|
init_esm_shims();
|
|
@@ -499,7 +499,7 @@ function renameIdentifier(node, oldName, newName) {
|
|
|
499
499
|
})
|
|
500
500
|
]).transformed[0];
|
|
501
501
|
}
|
|
502
|
-
function generateComponentSchemaFile(interfaces) {
|
|
502
|
+
function generateComponentSchemaFile(interfaces, includeOnly) {
|
|
503
503
|
const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });
|
|
504
504
|
const resultFile = ts.createSourceFile(
|
|
505
505
|
"component-schema.ts",
|
|
@@ -513,6 +513,9 @@ function generateComponentSchemaFile(interfaces) {
|
|
|
513
513
|
Object.entries(interfaces).forEach(([originalName, node]) => {
|
|
514
514
|
const pascalCaseName = toPascalCase(originalName);
|
|
515
515
|
typeNameMapping[originalName] = pascalCaseName;
|
|
516
|
+
if (includeOnly && !includeOnly.has(originalName)) {
|
|
517
|
+
return;
|
|
518
|
+
}
|
|
516
519
|
const renamedNode = renameIdentifier(node, originalName, pascalCaseName);
|
|
517
520
|
const printed = printer.printNode(ts.EmitHint.Unspecified, renamedNode, resultFile);
|
|
518
521
|
renamedInterfaces.push(printed);
|
|
@@ -551,7 +554,7 @@ function generateDoNotModifyFile() {
|
|
|
551
554
|
|
|
552
555
|
// src/services/api-code-generator.ts
|
|
553
556
|
init_esm_shims();
|
|
554
|
-
import
|
|
557
|
+
import ts3 from "typescript";
|
|
555
558
|
|
|
556
559
|
// src/services/endpoint-info-extractor.ts
|
|
557
560
|
init_esm_shims();
|
|
@@ -653,10 +656,46 @@ var EndpointInfoExtractor = class {
|
|
|
653
656
|
|
|
654
657
|
// src/generators/types-generator.ts
|
|
655
658
|
init_esm_shims();
|
|
659
|
+
import ts2 from "typescript";
|
|
656
660
|
var toPascalCase2 = (name) => {
|
|
657
661
|
return name.charAt(0).toUpperCase() + name.slice(1);
|
|
658
662
|
};
|
|
659
|
-
function
|
|
663
|
+
function renameIdentifier2(node, oldName, newName) {
|
|
664
|
+
return ts2.transform(node, [
|
|
665
|
+
(context) => (rootNode) => ts2.visitNode(rootNode, function visit(node2) {
|
|
666
|
+
if (ts2.isIdentifier(node2) && node2.text === oldName) {
|
|
667
|
+
return ts2.factory.createIdentifier(newName);
|
|
668
|
+
}
|
|
669
|
+
return ts2.visitEachChild(node2, visit, context);
|
|
670
|
+
})
|
|
671
|
+
]).transformed[0];
|
|
672
|
+
}
|
|
673
|
+
function prefixSharedSchemaRefs(node, allSchemaNames, localSchemaNames, declarationName) {
|
|
674
|
+
const sharedNames = /* @__PURE__ */ new Set();
|
|
675
|
+
for (const name of allSchemaNames) {
|
|
676
|
+
if (!localSchemaNames.has(name)) {
|
|
677
|
+
sharedNames.add(toPascalCase2(name));
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
return ts2.transform(node, [
|
|
681
|
+
(context) => (rootNode) => ts2.visitNode(rootNode, function visit(node2) {
|
|
682
|
+
if (ts2.isTypeReferenceNode(node2) && ts2.isIdentifier(node2.typeName)) {
|
|
683
|
+
const name = node2.typeName.text;
|
|
684
|
+
if (sharedNames.has(name) && name !== declarationName) {
|
|
685
|
+
const qualifiedName = ts2.factory.createQualifiedName(
|
|
686
|
+
ts2.factory.createIdentifier("Schema"),
|
|
687
|
+
ts2.factory.createIdentifier(name)
|
|
688
|
+
);
|
|
689
|
+
return ts2.factory.createTypeReferenceNode(qualifiedName, node2.typeArguments);
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
return ts2.visitEachChild(node2, visit, context);
|
|
693
|
+
})
|
|
694
|
+
]).transformed[0];
|
|
695
|
+
}
|
|
696
|
+
function generateTypesFile(endpointInfos, _options, schemaInterfaces, operationDefinitions, localSchemaOptions) {
|
|
697
|
+
const localSchemaNames = localSchemaOptions?.localSchemaNames ?? /* @__PURE__ */ new Set();
|
|
698
|
+
const localSchemaInterfaces = localSchemaOptions?.localSchemaInterfaces ?? {};
|
|
660
699
|
const schemaTypeMap = {};
|
|
661
700
|
if (schemaInterfaces) {
|
|
662
701
|
Object.keys(schemaInterfaces).forEach((actualTypeName) => {
|
|
@@ -671,23 +710,41 @@ function generateTypesFile(endpointInfos, _options, schemaInterfaces, operationD
|
|
|
671
710
|
}
|
|
672
711
|
});
|
|
673
712
|
}
|
|
713
|
+
const hasSharedSchemaTypes = schemaInterfaces && Object.keys(schemaInterfaces).some(
|
|
714
|
+
(name) => !localSchemaNames.has(name)
|
|
715
|
+
);
|
|
674
716
|
let importStatement = `/* eslint-disable */
|
|
675
|
-
// [Warning] Generated automatically - do not edit manually
|
|
676
|
-
|
|
717
|
+
// [Warning] Generated automatically - do not edit manually
|
|
718
|
+
|
|
677
719
|
`;
|
|
678
|
-
|
|
679
|
-
if (hasSchemaTypes) {
|
|
720
|
+
if (hasSharedSchemaTypes) {
|
|
680
721
|
importStatement += `import * as Schema from "../schema";
|
|
681
722
|
`;
|
|
682
723
|
}
|
|
683
724
|
importStatement += "\n";
|
|
684
725
|
const typeDefinitions = [];
|
|
726
|
+
if (Object.keys(localSchemaInterfaces).length > 0) {
|
|
727
|
+
const printer = ts2.createPrinter({ newLine: ts2.NewLineKind.LineFeed });
|
|
728
|
+
const resultFile = ts2.createSourceFile("types.ts", "", ts2.ScriptTarget.Latest, false, ts2.ScriptKind.TS);
|
|
729
|
+
const localTypeDefs = [];
|
|
730
|
+
const allSchemaNameSet = new Set(schemaInterfaces ? Object.keys(schemaInterfaces) : []);
|
|
731
|
+
for (const [originalName, node] of Object.entries(localSchemaInterfaces)) {
|
|
732
|
+
const pascalCaseName = toPascalCase2(originalName);
|
|
733
|
+
let transformedNode = renameIdentifier2(node, originalName, pascalCaseName);
|
|
734
|
+
transformedNode = prefixSharedSchemaRefs(transformedNode, allSchemaNameSet, localSchemaNames, pascalCaseName);
|
|
735
|
+
const printed = printer.printNode(ts2.EmitHint.Unspecified, transformedNode, resultFile);
|
|
736
|
+
localTypeDefs.push(printed);
|
|
737
|
+
}
|
|
738
|
+
if (localTypeDefs.length > 0) {
|
|
739
|
+
typeDefinitions.push(localTypeDefs.join("\n"));
|
|
740
|
+
}
|
|
741
|
+
}
|
|
685
742
|
const endpointTypes = [];
|
|
686
743
|
endpointInfos.forEach((endpoint) => {
|
|
687
744
|
const reqTypeName = endpoint.argTypeName;
|
|
688
745
|
const resTypeName = endpoint.responseTypeName;
|
|
689
746
|
if (reqTypeName) {
|
|
690
|
-
const requestTypeContent = generateRequestTypeContent(endpoint, operationDefinitions, schemaTypeMap);
|
|
747
|
+
const requestTypeContent = generateRequestTypeContent(endpoint, operationDefinitions, schemaTypeMap, localSchemaNames);
|
|
691
748
|
if (requestTypeContent.trim() === "") {
|
|
692
749
|
endpointTypes.push(
|
|
693
750
|
`export type ${reqTypeName} = void;`,
|
|
@@ -703,7 +760,7 @@ function generateTypesFile(endpointInfos, _options, schemaInterfaces, operationD
|
|
|
703
760
|
}
|
|
704
761
|
}
|
|
705
762
|
if (resTypeName) {
|
|
706
|
-
const responseTypeResult = generateResponseTypeContent(endpoint, operationDefinitions, schemaTypeMap);
|
|
763
|
+
const responseTypeResult = generateResponseTypeContent(endpoint, operationDefinitions, schemaTypeMap, localSchemaNames);
|
|
707
764
|
if (responseTypeResult.content.trim() === "") {
|
|
708
765
|
endpointTypes.push(
|
|
709
766
|
`export type ${resTypeName} = void;`,
|
|
@@ -736,19 +793,19 @@ function generateTypesFile(endpointInfos, _options, schemaInterfaces, operationD
|
|
|
736
793
|
}
|
|
737
794
|
return importStatement + typeDefinitions.join("\n\n");
|
|
738
795
|
}
|
|
739
|
-
function generateRequestTypeContent(endpoint, operationDefinitions, schemaTypeMap = {}) {
|
|
796
|
+
function generateRequestTypeContent(endpoint, operationDefinitions, schemaTypeMap = {}, localSchemaNames = /* @__PURE__ */ new Set()) {
|
|
740
797
|
const properties = [];
|
|
741
798
|
if (endpoint.queryParams && endpoint.queryParams.length > 0) {
|
|
742
799
|
endpoint.queryParams.forEach((param) => {
|
|
743
800
|
const optional = param.required ? "" : "?";
|
|
744
|
-
const paramType = getTypeFromParameter(param, schemaTypeMap);
|
|
801
|
+
const paramType = getTypeFromParameter(param, schemaTypeMap, localSchemaNames);
|
|
745
802
|
properties.push(` ${param.name}${optional}: ${paramType};`);
|
|
746
803
|
});
|
|
747
804
|
}
|
|
748
805
|
if (endpoint.pathParams && endpoint.pathParams.length > 0) {
|
|
749
806
|
endpoint.pathParams.forEach((param) => {
|
|
750
807
|
const optional = param.required ? "" : "?";
|
|
751
|
-
const paramType = getTypeFromParameter(param, schemaTypeMap);
|
|
808
|
+
const paramType = getTypeFromParameter(param, schemaTypeMap, localSchemaNames);
|
|
752
809
|
properties.push(` ${param.name}${optional}: ${paramType};`);
|
|
753
810
|
});
|
|
754
811
|
}
|
|
@@ -762,15 +819,15 @@ function generateRequestTypeContent(endpoint, operationDefinitions, schemaTypeMa
|
|
|
762
819
|
const jsonContent = content["application/json"] || content["*/*"];
|
|
763
820
|
const formContent = content["multipart/form-data"] || content["application/x-www-form-urlencoded"];
|
|
764
821
|
if (jsonContent?.schema) {
|
|
765
|
-
const bodyType = getTypeFromSchema(jsonContent.schema, schemaTypeMap, 1);
|
|
822
|
+
const bodyType = getTypeFromSchema(jsonContent.schema, schemaTypeMap, 1, localSchemaNames);
|
|
766
823
|
properties.push(` body: ${bodyType};`);
|
|
767
824
|
} else if (formContent?.schema) {
|
|
768
|
-
const bodyType = getTypeFromSchema(formContent.schema, schemaTypeMap, 1);
|
|
825
|
+
const bodyType = getTypeFromSchema(formContent.schema, schemaTypeMap, 1, localSchemaNames);
|
|
769
826
|
properties.push(` body: ${bodyType};`);
|
|
770
827
|
} else {
|
|
771
828
|
const firstContent = Object.values(content)[0];
|
|
772
829
|
if (firstContent?.schema) {
|
|
773
|
-
const bodyType = getTypeFromSchema(firstContent.schema, schemaTypeMap, 1);
|
|
830
|
+
const bodyType = getTypeFromSchema(firstContent.schema, schemaTypeMap, 1, localSchemaNames);
|
|
774
831
|
properties.push(` body: ${bodyType};`);
|
|
775
832
|
} else {
|
|
776
833
|
properties.push(` body?: any; // Request body from OpenAPI`);
|
|
@@ -782,7 +839,7 @@ function generateRequestTypeContent(endpoint, operationDefinitions, schemaTypeMa
|
|
|
782
839
|
}
|
|
783
840
|
return properties.join("\n");
|
|
784
841
|
}
|
|
785
|
-
function generateResponseTypeContent(endpoint, operationDefinitions, schemaTypeMap = {}) {
|
|
842
|
+
function generateResponseTypeContent(endpoint, operationDefinitions, schemaTypeMap = {}, localSchemaNames = /* @__PURE__ */ new Set()) {
|
|
786
843
|
const operationDef = operationDefinitions?.find((op) => {
|
|
787
844
|
return op.operation?.operationId === endpoint.operationName || op.operation?.operationId === endpoint.operationName.toLowerCase() || // 也嘗試匹配 verb + path 組合
|
|
788
845
|
op.verb === endpoint.verb.toLowerCase() && op.path === endpoint.path;
|
|
@@ -794,12 +851,12 @@ function generateResponseTypeContent(endpoint, operationDefinitions, schemaTypeM
|
|
|
794
851
|
if (jsonContent?.schema) {
|
|
795
852
|
const schema = jsonContent.schema;
|
|
796
853
|
if (schema.$ref || schema.type !== "object" || !schema.properties) {
|
|
797
|
-
const directType = getTypeFromSchema(schema, schemaTypeMap, 0);
|
|
854
|
+
const directType = getTypeFromSchema(schema, schemaTypeMap, 0, localSchemaNames);
|
|
798
855
|
if (directType && directType !== "any") {
|
|
799
856
|
return { content: directType, isDirectType: true };
|
|
800
857
|
}
|
|
801
858
|
}
|
|
802
|
-
const responseProps = parseSchemaProperties(schema, schemaTypeMap);
|
|
859
|
+
const responseProps = parseSchemaProperties(schema, schemaTypeMap, localSchemaNames);
|
|
803
860
|
if (responseProps.length > 0) {
|
|
804
861
|
return { content: responseProps.join("\n"), isDirectType: false };
|
|
805
862
|
}
|
|
@@ -808,14 +865,14 @@ function generateResponseTypeContent(endpoint, operationDefinitions, schemaTypeM
|
|
|
808
865
|
}
|
|
809
866
|
return { content: "", isDirectType: false };
|
|
810
867
|
}
|
|
811
|
-
function parseSchemaProperties(schema, schemaTypeMap = {}) {
|
|
868
|
+
function parseSchemaProperties(schema, schemaTypeMap = {}, localSchemaNames = /* @__PURE__ */ new Set()) {
|
|
812
869
|
const properties = [];
|
|
813
870
|
if (schema.type === "object" && schema.properties) {
|
|
814
871
|
const required = schema.required || [];
|
|
815
872
|
Object.entries(schema.properties).forEach(([propName, propSchema]) => {
|
|
816
873
|
const isRequired = required.includes(propName);
|
|
817
874
|
const optional = isRequired ? "" : "?";
|
|
818
|
-
const propType = getTypeFromSchema(propSchema, schemaTypeMap, 1);
|
|
875
|
+
const propType = getTypeFromSchema(propSchema, schemaTypeMap, 1, localSchemaNames);
|
|
819
876
|
const needsQuotes = /[^a-zA-Z0-9_$]/.test(propName);
|
|
820
877
|
const quotedPropName = needsQuotes ? `"${propName}"` : propName;
|
|
821
878
|
if (propSchema.description) {
|
|
@@ -826,7 +883,7 @@ function parseSchemaProperties(schema, schemaTypeMap = {}) {
|
|
|
826
883
|
}
|
|
827
884
|
return properties;
|
|
828
885
|
}
|
|
829
|
-
function getTypeFromSchema(schema, schemaTypeMap = {}, indentLevel = 0) {
|
|
886
|
+
function getTypeFromSchema(schema, schemaTypeMap = {}, indentLevel = 0, localSchemaNames = /* @__PURE__ */ new Set()) {
|
|
830
887
|
if (!schema) return "any";
|
|
831
888
|
if (schema.$ref) {
|
|
832
889
|
const refPath = schema.$ref;
|
|
@@ -834,7 +891,7 @@ function getTypeFromSchema(schema, schemaTypeMap = {}, indentLevel = 0) {
|
|
|
834
891
|
const originalTypeName = refPath.replace("#/components/schemas/", "");
|
|
835
892
|
const actualTypeName = schemaTypeMap[originalTypeName] || originalTypeName;
|
|
836
893
|
const pascalCaseTypeName = toPascalCase2(actualTypeName);
|
|
837
|
-
const baseType2 = `Schema.${pascalCaseTypeName}`;
|
|
894
|
+
const baseType2 = localSchemaNames.has(originalTypeName) ? pascalCaseTypeName : `Schema.${pascalCaseTypeName}`;
|
|
838
895
|
return schema.nullable ? `${baseType2} | null` : baseType2;
|
|
839
896
|
}
|
|
840
897
|
}
|
|
@@ -857,7 +914,7 @@ function getTypeFromSchema(schema, schemaTypeMap = {}, indentLevel = 0) {
|
|
|
857
914
|
baseType = "boolean";
|
|
858
915
|
break;
|
|
859
916
|
case "array":
|
|
860
|
-
const itemType = schema.items ? getTypeFromSchema(schema.items, schemaTypeMap, indentLevel) : "any";
|
|
917
|
+
const itemType = schema.items ? getTypeFromSchema(schema.items, schemaTypeMap, indentLevel, localSchemaNames) : "any";
|
|
861
918
|
const needsParentheses = itemType.includes("|");
|
|
862
919
|
baseType = needsParentheses ? `(${itemType})[]` : `${itemType}[]`;
|
|
863
920
|
break;
|
|
@@ -866,7 +923,7 @@ function getTypeFromSchema(schema, schemaTypeMap = {}, indentLevel = 0) {
|
|
|
866
923
|
const entries = Object.entries(schema.properties);
|
|
867
924
|
if (entries.length === 0) {
|
|
868
925
|
if (schema.additionalProperties) {
|
|
869
|
-
const valueType = schema.additionalProperties === true ? "any" : getTypeFromSchema(schema.additionalProperties, schemaTypeMap, indentLevel);
|
|
926
|
+
const valueType = schema.additionalProperties === true ? "any" : getTypeFromSchema(schema.additionalProperties, schemaTypeMap, indentLevel, localSchemaNames);
|
|
870
927
|
baseType = `Record<string, ${valueType}>`;
|
|
871
928
|
} else {
|
|
872
929
|
baseType = "{}";
|
|
@@ -878,7 +935,7 @@ function getTypeFromSchema(schema, schemaTypeMap = {}, indentLevel = 0) {
|
|
|
878
935
|
entries.forEach(([key, propSchema]) => {
|
|
879
936
|
const required = schema.required || [];
|
|
880
937
|
const optional = required.includes(key) ? "" : "?";
|
|
881
|
-
const type = getTypeFromSchema(propSchema, schemaTypeMap, indentLevel + 1);
|
|
938
|
+
const type = getTypeFromSchema(propSchema, schemaTypeMap, indentLevel + 1, localSchemaNames);
|
|
882
939
|
const needsQuotes = /[^a-zA-Z0-9_$]/.test(key);
|
|
883
940
|
const quotedKey = needsQuotes ? `"${key}"` : key;
|
|
884
941
|
if (propSchema.description) {
|
|
@@ -891,7 +948,7 @@ ${props.join("\n")}
|
|
|
891
948
|
${currentIndent}}`;
|
|
892
949
|
}
|
|
893
950
|
} else if (schema.additionalProperties) {
|
|
894
|
-
const valueType = schema.additionalProperties === true ? "any" : getTypeFromSchema(schema.additionalProperties, schemaTypeMap, indentLevel);
|
|
951
|
+
const valueType = schema.additionalProperties === true ? "any" : getTypeFromSchema(schema.additionalProperties, schemaTypeMap, indentLevel, localSchemaNames);
|
|
895
952
|
baseType = `Record<string, ${valueType}>`;
|
|
896
953
|
} else {
|
|
897
954
|
baseType = "any";
|
|
@@ -903,9 +960,9 @@ ${currentIndent}}`;
|
|
|
903
960
|
}
|
|
904
961
|
return schema.nullable ? `${baseType} | null` : baseType;
|
|
905
962
|
}
|
|
906
|
-
function getTypeFromParameter(param, schemaTypeMap = {}) {
|
|
963
|
+
function getTypeFromParameter(param, schemaTypeMap = {}, localSchemaNames = /* @__PURE__ */ new Set()) {
|
|
907
964
|
if (!param.schema) return "any";
|
|
908
|
-
return getTypeFromSchema(param.schema, schemaTypeMap);
|
|
965
|
+
return getTypeFromSchema(param.schema, schemaTypeMap, 0, localSchemaNames);
|
|
909
966
|
}
|
|
910
967
|
|
|
911
968
|
// src/generators/rtk-query-generator.ts
|
|
@@ -1102,7 +1159,7 @@ var ApiCodeGenerator = class {
|
|
|
1102
1159
|
};
|
|
1103
1160
|
const apiGen = this.parserService.getApiGenerator();
|
|
1104
1161
|
const schemaInterfaces = apiGen.aliases.reduce((curr, alias) => {
|
|
1105
|
-
if (
|
|
1162
|
+
if (ts3.isInterfaceDeclaration(alias) || ts3.isTypeAliasDeclaration(alias)) {
|
|
1106
1163
|
const name = alias.name.text;
|
|
1107
1164
|
return {
|
|
1108
1165
|
...curr,
|
|
@@ -1186,6 +1243,150 @@ ${enumEntries}
|
|
|
1186
1243
|
`;
|
|
1187
1244
|
}
|
|
1188
1245
|
|
|
1246
|
+
// src/utils/schema-ref-analyzer.ts
|
|
1247
|
+
init_esm_shims();
|
|
1248
|
+
function collectRefsFromSchema(schema, refs) {
|
|
1249
|
+
if (!schema || typeof schema !== "object") return;
|
|
1250
|
+
if (schema.$ref && typeof schema.$ref === "string") {
|
|
1251
|
+
const match = schema.$ref.match(/^#\/components\/schemas\/(.+)$/);
|
|
1252
|
+
if (match) {
|
|
1253
|
+
refs.add(match[1]);
|
|
1254
|
+
}
|
|
1255
|
+
}
|
|
1256
|
+
if (schema.properties) {
|
|
1257
|
+
for (const prop of Object.values(schema.properties)) {
|
|
1258
|
+
collectRefsFromSchema(prop, refs);
|
|
1259
|
+
}
|
|
1260
|
+
}
|
|
1261
|
+
if (schema.items) {
|
|
1262
|
+
collectRefsFromSchema(schema.items, refs);
|
|
1263
|
+
}
|
|
1264
|
+
if (schema.additionalProperties && typeof schema.additionalProperties === "object") {
|
|
1265
|
+
collectRefsFromSchema(schema.additionalProperties, refs);
|
|
1266
|
+
}
|
|
1267
|
+
for (const key of ["allOf", "oneOf", "anyOf"]) {
|
|
1268
|
+
if (Array.isArray(schema[key])) {
|
|
1269
|
+
for (const item of schema[key]) {
|
|
1270
|
+
collectRefsFromSchema(item, refs);
|
|
1271
|
+
}
|
|
1272
|
+
}
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1275
|
+
function collectDirectRefs(operationDefs) {
|
|
1276
|
+
const refs = /* @__PURE__ */ new Set();
|
|
1277
|
+
for (const opDef of operationDefs) {
|
|
1278
|
+
const op = opDef.operation;
|
|
1279
|
+
if (op.parameters) {
|
|
1280
|
+
for (const param of op.parameters) {
|
|
1281
|
+
const p = param;
|
|
1282
|
+
if (p.schema) {
|
|
1283
|
+
collectRefsFromSchema(p.schema, refs);
|
|
1284
|
+
}
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
1287
|
+
if (op.requestBody) {
|
|
1288
|
+
const rb = op.requestBody;
|
|
1289
|
+
if (rb.content) {
|
|
1290
|
+
for (const ct of Object.values(rb.content)) {
|
|
1291
|
+
if (ct.schema) {
|
|
1292
|
+
collectRefsFromSchema(ct.schema, refs);
|
|
1293
|
+
}
|
|
1294
|
+
}
|
|
1295
|
+
}
|
|
1296
|
+
}
|
|
1297
|
+
if (op.responses) {
|
|
1298
|
+
for (const resp of Object.values(op.responses)) {
|
|
1299
|
+
const r = resp;
|
|
1300
|
+
if (r.content) {
|
|
1301
|
+
for (const ct of Object.values(r.content)) {
|
|
1302
|
+
if (ct.schema) {
|
|
1303
|
+
collectRefsFromSchema(ct.schema, refs);
|
|
1304
|
+
}
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
}
|
|
1308
|
+
}
|
|
1309
|
+
}
|
|
1310
|
+
return refs;
|
|
1311
|
+
}
|
|
1312
|
+
function resolveTransitiveDeps(directRefs, allSchemas) {
|
|
1313
|
+
const resolved = /* @__PURE__ */ new Set();
|
|
1314
|
+
const queue = [...directRefs];
|
|
1315
|
+
while (queue.length > 0) {
|
|
1316
|
+
const name = queue.pop();
|
|
1317
|
+
if (resolved.has(name)) continue;
|
|
1318
|
+
resolved.add(name);
|
|
1319
|
+
const schema = allSchemas[name];
|
|
1320
|
+
if (!schema) continue;
|
|
1321
|
+
const nestedRefs = /* @__PURE__ */ new Set();
|
|
1322
|
+
collectRefsFromSchema(schema, nestedRefs);
|
|
1323
|
+
for (const ref of nestedRefs) {
|
|
1324
|
+
if (!resolved.has(ref)) {
|
|
1325
|
+
queue.push(ref);
|
|
1326
|
+
}
|
|
1327
|
+
}
|
|
1328
|
+
}
|
|
1329
|
+
return resolved;
|
|
1330
|
+
}
|
|
1331
|
+
function analyzeSchemaRefs(groupOperations, allSchemas, allSchemaNames) {
|
|
1332
|
+
const groupRefs = /* @__PURE__ */ new Map();
|
|
1333
|
+
for (const [groupKey, opDefs] of groupOperations) {
|
|
1334
|
+
const directRefs = collectDirectRefs(opDefs);
|
|
1335
|
+
const fullRefs = resolveTransitiveDeps(directRefs, allSchemas);
|
|
1336
|
+
groupRefs.set(groupKey, fullRefs);
|
|
1337
|
+
}
|
|
1338
|
+
const refCountMap = /* @__PURE__ */ new Map();
|
|
1339
|
+
for (const [groupKey, refs] of groupRefs) {
|
|
1340
|
+
for (const schemaName of refs) {
|
|
1341
|
+
if (!refCountMap.has(schemaName)) {
|
|
1342
|
+
refCountMap.set(schemaName, /* @__PURE__ */ new Set());
|
|
1343
|
+
}
|
|
1344
|
+
refCountMap.get(schemaName).add(groupKey);
|
|
1345
|
+
}
|
|
1346
|
+
}
|
|
1347
|
+
const sharedSchemas = /* @__PURE__ */ new Set();
|
|
1348
|
+
const groupLocalSchemas = /* @__PURE__ */ new Map();
|
|
1349
|
+
const unusedSchemas = /* @__PURE__ */ new Set();
|
|
1350
|
+
for (const schemaName of allSchemaNames) {
|
|
1351
|
+
const groups = refCountMap.get(schemaName);
|
|
1352
|
+
if (!groups || groups.size === 0) {
|
|
1353
|
+
unusedSchemas.add(schemaName);
|
|
1354
|
+
} else if (groups.size === 1) {
|
|
1355
|
+
const groupKey = [...groups][0];
|
|
1356
|
+
if (!groupLocalSchemas.has(groupKey)) {
|
|
1357
|
+
groupLocalSchemas.set(groupKey, /* @__PURE__ */ new Set());
|
|
1358
|
+
}
|
|
1359
|
+
groupLocalSchemas.get(groupKey).add(schemaName);
|
|
1360
|
+
} else {
|
|
1361
|
+
sharedSchemas.add(schemaName);
|
|
1362
|
+
}
|
|
1363
|
+
}
|
|
1364
|
+
let changed = true;
|
|
1365
|
+
while (changed) {
|
|
1366
|
+
changed = false;
|
|
1367
|
+
for (const [groupKey, localSchemas] of groupLocalSchemas) {
|
|
1368
|
+
for (const schemaName of [...localSchemas]) {
|
|
1369
|
+
const schema = allSchemas[schemaName];
|
|
1370
|
+
if (!schema) continue;
|
|
1371
|
+
const deps = /* @__PURE__ */ new Set();
|
|
1372
|
+
collectRefsFromSchema(schema, deps);
|
|
1373
|
+
for (const dep of deps) {
|
|
1374
|
+
for (const [otherGroup, otherLocals] of groupLocalSchemas) {
|
|
1375
|
+
if (otherGroup !== groupKey && otherLocals.has(dep)) {
|
|
1376
|
+
sharedSchemas.add(dep);
|
|
1377
|
+
sharedSchemas.add(schemaName);
|
|
1378
|
+
otherLocals.delete(dep);
|
|
1379
|
+
localSchemas.delete(schemaName);
|
|
1380
|
+
changed = true;
|
|
1381
|
+
}
|
|
1382
|
+
}
|
|
1383
|
+
}
|
|
1384
|
+
}
|
|
1385
|
+
}
|
|
1386
|
+
}
|
|
1387
|
+
return { sharedSchemas, groupLocalSchemas, unusedSchemas };
|
|
1388
|
+
}
|
|
1389
|
+
|
|
1189
1390
|
// src/services/unified-code-generator.ts
|
|
1190
1391
|
var UnifiedCodeGenerator = class {
|
|
1191
1392
|
_options;
|
|
@@ -1208,6 +1409,10 @@ var UnifiedCodeGenerator = class {
|
|
|
1208
1409
|
};
|
|
1209
1410
|
// 收集所有 tags
|
|
1210
1411
|
allTags = /* @__PURE__ */ new Set();
|
|
1412
|
+
// 收集每個 group 的 operation definitions(用於 schema 引用分析)
|
|
1413
|
+
groupOperationDefs = /* @__PURE__ */ new Map();
|
|
1414
|
+
// 收集每個 group 的生成選項(用於重新生成 types)
|
|
1415
|
+
groupGenerationOptions = /* @__PURE__ */ new Map();
|
|
1211
1416
|
constructor(options) {
|
|
1212
1417
|
this._options = options;
|
|
1213
1418
|
}
|
|
@@ -1217,6 +1422,7 @@ var UnifiedCodeGenerator = class {
|
|
|
1217
1422
|
async generateAll() {
|
|
1218
1423
|
await this.prepare();
|
|
1219
1424
|
await this.generateApi();
|
|
1425
|
+
this.splitSchemaByUsage();
|
|
1220
1426
|
this.generateCommonTypesContent();
|
|
1221
1427
|
this.generateSchemaContent();
|
|
1222
1428
|
this.generateUtilsContent();
|
|
@@ -1243,7 +1449,7 @@ var UnifiedCodeGenerator = class {
|
|
|
1243
1449
|
this.parserService.initialize();
|
|
1244
1450
|
const apiGen = this.parserService.getApiGenerator();
|
|
1245
1451
|
this.schemaInterfaces = apiGen.aliases.reduce((curr, alias) => {
|
|
1246
|
-
if (
|
|
1452
|
+
if (ts4.isInterfaceDeclaration(alias) || ts4.isTypeAliasDeclaration(alias)) {
|
|
1247
1453
|
const name = alias.name.text;
|
|
1248
1454
|
return {
|
|
1249
1455
|
...curr,
|
|
@@ -1283,6 +1489,55 @@ var UnifiedCodeGenerator = class {
|
|
|
1283
1489
|
}
|
|
1284
1490
|
}
|
|
1285
1491
|
}
|
|
1492
|
+
/**
|
|
1493
|
+
* 分析 schema 引用,將只被單一 group 使用的 schema 移到該 group 的 types.ts
|
|
1494
|
+
*/
|
|
1495
|
+
splitSchemaByUsage() {
|
|
1496
|
+
if (!this.openApiDoc || this.groupOperationDefs.size === 0) return;
|
|
1497
|
+
const rawSchemas = this.openApiDoc.components?.schemas ?? {};
|
|
1498
|
+
const allSchemaNames = Object.keys(this.schemaInterfaces);
|
|
1499
|
+
const analysis = analyzeSchemaRefs(
|
|
1500
|
+
this.groupOperationDefs,
|
|
1501
|
+
rawSchemas,
|
|
1502
|
+
allSchemaNames
|
|
1503
|
+
);
|
|
1504
|
+
this.sharedSchemaNames = analysis.sharedSchemas;
|
|
1505
|
+
for (const group of this.generatedContent.groups) {
|
|
1506
|
+
const localNames = analysis.groupLocalSchemas.get(group.groupKey);
|
|
1507
|
+
if (!localNames || localNames.size === 0) continue;
|
|
1508
|
+
const groupOptions = this.groupGenerationOptions.get(group.groupKey);
|
|
1509
|
+
if (!groupOptions || !this.parserService) continue;
|
|
1510
|
+
const localSchemaInterfaces = {};
|
|
1511
|
+
for (const name of localNames) {
|
|
1512
|
+
if (this.schemaInterfaces[name]) {
|
|
1513
|
+
localSchemaInterfaces[name] = this.schemaInterfaces[name];
|
|
1514
|
+
}
|
|
1515
|
+
}
|
|
1516
|
+
const infoExtractor = new EndpointInfoExtractor(groupOptions);
|
|
1517
|
+
const operationDefs = this.groupOperationDefs.get(group.groupKey) ?? [];
|
|
1518
|
+
const endpointInfos = infoExtractor.extractEndpointInfos(operationDefs);
|
|
1519
|
+
const generatorOptions = {
|
|
1520
|
+
...groupOptions,
|
|
1521
|
+
apiConfiguration: groupOptions.apiConfiguration || {
|
|
1522
|
+
file: "@/store/webapi",
|
|
1523
|
+
importName: "WebApiConfiguration"
|
|
1524
|
+
}
|
|
1525
|
+
};
|
|
1526
|
+
const newTypesContent = generateTypesFile(
|
|
1527
|
+
endpointInfos,
|
|
1528
|
+
generatorOptions,
|
|
1529
|
+
this.schemaInterfaces,
|
|
1530
|
+
operationDefs,
|
|
1531
|
+
{
|
|
1532
|
+
localSchemaInterfaces,
|
|
1533
|
+
localSchemaNames: localNames
|
|
1534
|
+
}
|
|
1535
|
+
);
|
|
1536
|
+
group.content.files.types = newTypesContent;
|
|
1537
|
+
}
|
|
1538
|
+
}
|
|
1539
|
+
// 儲存 shared schema 名稱(只有這些會寫入 schema.ts)
|
|
1540
|
+
sharedSchemaNames = null;
|
|
1286
1541
|
/**
|
|
1287
1542
|
* 生成 common types
|
|
1288
1543
|
*/
|
|
@@ -1290,10 +1545,13 @@ var UnifiedCodeGenerator = class {
|
|
|
1290
1545
|
this.generatedContent.commonTypes = generateCommonTypesFile();
|
|
1291
1546
|
}
|
|
1292
1547
|
/**
|
|
1293
|
-
* 生成Schema
|
|
1548
|
+
* 生成Schema(只包含 shared types,排除 group-local 和未使用的 types)
|
|
1294
1549
|
*/
|
|
1295
1550
|
async generateSchemaContent() {
|
|
1296
|
-
this.generatedContent.componentSchema = generateComponentSchemaFile(
|
|
1551
|
+
this.generatedContent.componentSchema = generateComponentSchemaFile(
|
|
1552
|
+
this.schemaInterfaces,
|
|
1553
|
+
this.sharedSchemaNames ?? void 0
|
|
1554
|
+
);
|
|
1297
1555
|
}
|
|
1298
1556
|
/**
|
|
1299
1557
|
* 生成 DO_NOT_MODIFY.md
|
|
@@ -1401,6 +1659,9 @@ var UnifiedCodeGenerator = class {
|
|
|
1401
1659
|
if (!this.openApiDoc || !this.parserService) {
|
|
1402
1660
|
throw new Error("OpenAPI \u6587\u6A94\u672A\u521D\u59CB\u5316\uFF0C\u8ACB\u5148\u8ABF\u7528 prepare()");
|
|
1403
1661
|
}
|
|
1662
|
+
const groupOpDefs = this.parserService.getOperationDefinitions(groupOptions.filterEndpoints);
|
|
1663
|
+
this.groupOperationDefs.set(groupInfo.groupKey, groupOpDefs);
|
|
1664
|
+
this.groupGenerationOptions.set(groupInfo.groupKey, groupOptions);
|
|
1404
1665
|
const apiGenerator = new ApiCodeGenerator(this.parserService, groupOptions);
|
|
1405
1666
|
const result = await apiGenerator.generate();
|
|
1406
1667
|
return result;
|
|
@@ -1409,11 +1670,12 @@ var UnifiedCodeGenerator = class {
|
|
|
1409
1670
|
* 生成主 index.ts 檔案
|
|
1410
1671
|
*/
|
|
1411
1672
|
generateMainIndex(generatedGroups) {
|
|
1412
|
-
const
|
|
1673
|
+
const groupExports = generatedGroups.map((groupKey) => `export * from "./${groupKey}";`).join("\n");
|
|
1413
1674
|
return `/* eslint-disable */
|
|
1414
1675
|
// [Warning] Generated automatically - do not edit manually
|
|
1415
1676
|
|
|
1416
|
-
|
|
1677
|
+
export * from "./schema";
|
|
1678
|
+
${groupExports}
|
|
1417
1679
|
`;
|
|
1418
1680
|
}
|
|
1419
1681
|
};
|