@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/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 import_typescript3 = __toESM(require("typescript"));
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 generateComponentSchemaFile(interfaces) {
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 import_typescript2 = __toESM(require("typescript"));
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 generateTypesFile(endpointInfos, _options, schemaInterfaces, operationDefinitions) {
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
- const hasSchemaTypes = schemaInterfaces && Object.keys(schemaInterfaces).length > 0;
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 (import_typescript2.default.isInterfaceDeclaration(alias) || import_typescript2.default.isTypeAliasDeclaration(alias)) {
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 (import_typescript3.default.isInterfaceDeclaration(alias) || import_typescript3.default.isTypeAliasDeclaration(alias)) {
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(this.schemaInterfaces);
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 exports2 = generatedGroups.map((groupKey) => `export * from "./${groupKey}";`).join("\n");
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
- ${exports2}
1748
+ export * from "./schema";
1749
+ ${groupExports}
1432
1750
  `;
1433
1751
  }
1434
1752
  };