@acrool/rtk-query-codegen-openapi 1.3.0 → 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/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 ts3 from "typescript";
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 ts2 from "typescript";
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 generateTypesFile(endpointInfos, _options, schemaInterfaces, operationDefinitions) {
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
- const hasSchemaTypes = schemaInterfaces && Object.keys(schemaInterfaces).length > 0;
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 (ts2.isInterfaceDeclaration(alias) || ts2.isTypeAliasDeclaration(alias)) {
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 (ts3.isInterfaceDeclaration(alias) || ts3.isTypeAliasDeclaration(alias)) {
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(this.schemaInterfaces);
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 exports = generatedGroups.map((groupKey) => `export * from "./${groupKey}";`).join("\n");
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
- ${exports}
1677
+ export * from "./schema";
1678
+ ${groupExports}
1417
1679
  `;
1418
1680
  }
1419
1681
  };