@acrool/rtk-query-codegen-openapi 0.0.2 → 0.0.6

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
@@ -305,14 +305,14 @@ function removeUndefined(t) {
305
305
 
306
306
  // src/generators/react-hooks.ts
307
307
  var createBinding = ({
308
- operationDefinition: { verb, path: path4, operation },
308
+ operationDefinition: { verb, path: path4 },
309
309
  overrides,
310
310
  isLazy = false
311
311
  }) => factory.createBindingElement(
312
312
  void 0,
313
313
  void 0,
314
314
  factory.createIdentifier(
315
- `use${isLazy ? "Lazy" : ""}${capitalize(getOperationName(verb, path4, operation.operationId))}${isQuery(verb, overrides) ? "Query" : "Mutation"}`
315
+ `use${isLazy ? "Lazy" : ""}${capitalize(getOperationName(verb, path4, void 0))}${isQuery(verb, overrides) ? "Query" : "Mutation"}`
316
316
  ),
317
317
  void 0
318
318
  );
@@ -366,8 +366,8 @@ function defaultIsDataResponse(code, includeDefault) {
366
366
  const parsedCode = Number(code);
367
367
  return !Number.isNaN(parsedCode) && parsedCode >= 200 && parsedCode < 300;
368
368
  }
369
- function getOperationName2({ verb, path: path4, operation }) {
370
- return _getOperationName(verb, path4, operation.operationId);
369
+ function getOperationName2({ verb, path: path4 }) {
370
+ return _getOperationName(verb, path4, void 0);
371
371
  }
372
372
  function getTags({ verb, pathItem }) {
373
373
  return verb ? pathItem[verb]?.tags || [] : [];
@@ -441,41 +441,153 @@ async function generateApi(spec, {
441
441
  useEnumType,
442
442
  mergeReadWriteOnly
443
443
  });
444
+ const schemeTypeNames = /* @__PURE__ */ new Set();
445
+ function addSchemeTypeName(name) {
446
+ schemeTypeNames.add(name);
447
+ schemeTypeNames.add(camelCase(name));
448
+ schemeTypeNames.add(capitalize(camelCase(name)));
449
+ }
444
450
  if (sharedTypesFile) {
451
+ const resultFile2 = ts4.createSourceFile(
452
+ "sharedTypes.ts",
453
+ "",
454
+ ts4.ScriptTarget.Latest,
455
+ /*setParentNodes*/
456
+ false,
457
+ ts4.ScriptKind.TS
458
+ );
459
+ const printer2 = ts4.createPrinter({ newLine: ts4.NewLineKind.LineFeed });
460
+ const allTypeDefinitions = [];
461
+ const definedTypeNames = /* @__PURE__ */ new Set();
445
462
  const components = v3Doc.components;
446
463
  if (components) {
447
- const resultFile2 = ts4.createSourceFile(
448
- "sharedTypes.ts",
449
- "",
450
- ts4.ScriptTarget.Latest,
451
- /*setParentNodes*/
452
- false,
453
- ts4.ScriptKind.TS
454
- );
455
- const printer2 = ts4.createPrinter({ newLine: ts4.NewLineKind.LineFeed });
456
- const typeDefinitions = Object.entries(components).flatMap(([_, componentDefs]) => {
457
- return Object.entries(componentDefs).map(([name, def]) => {
458
- const typeNode = apiGen.getTypeFromSchema(def);
464
+ const componentDefinitions = Object.entries(components).map(([componentType, componentDefs]) => {
465
+ const typeEntries = Object.entries(componentDefs).map(([name, def]) => {
466
+ addSchemeTypeName(name);
467
+ const typeName = capitalize(camelCase(name));
468
+ definedTypeNames.add(typeName);
469
+ const typeNode = wrapWithSchemeIfComponent(apiGen.getTypeFromSchema(def));
459
470
  return factory.createTypeAliasDeclaration(
460
471
  [factory.createModifier(ts4.SyntaxKind.ExportKeyword)],
461
- factory.createIdentifier(name),
472
+ factory.createIdentifier(typeName),
462
473
  void 0,
463
474
  typeNode
464
475
  );
465
476
  });
477
+ return factory.createModuleDeclaration(
478
+ [factory.createModifier(ts4.SyntaxKind.ExportKeyword)],
479
+ factory.createIdentifier("Scheme"),
480
+ factory.createModuleBlock(typeEntries),
481
+ ts4.NodeFlags.Namespace
482
+ );
466
483
  });
467
- const output = printer2.printNode(
468
- ts4.EmitHint.Unspecified,
469
- factory.createSourceFile(
470
- typeDefinitions,
471
- factory.createToken(ts4.SyntaxKind.EndOfFileToken),
472
- ts4.NodeFlags.None
473
- ),
474
- resultFile2
484
+ allTypeDefinitions.push(...componentDefinitions);
485
+ }
486
+ const enumEntries = [
487
+ ...apiGen.enumAliases.filter((e) => ts4.isEnumDeclaration(e)),
488
+ ...apiGen.enumAliases.filter((e) => ts4.isTypeAliasDeclaration(e))
489
+ ].map((enumDecl) => {
490
+ if (ts4.isEnumDeclaration(enumDecl)) {
491
+ return factory.createEnumDeclaration(
492
+ [factory.createModifier(ts4.SyntaxKind.ExportKeyword)],
493
+ enumDecl.name,
494
+ enumDecl.members
495
+ );
496
+ } else if (ts4.isTypeAliasDeclaration(enumDecl)) {
497
+ return factory.createTypeAliasDeclaration(
498
+ [factory.createModifier(ts4.SyntaxKind.ExportKeyword)],
499
+ enumDecl.name,
500
+ enumDecl.typeParameters,
501
+ enumDecl.type
502
+ );
503
+ }
504
+ return enumDecl;
505
+ });
506
+ const unionTypeEnums = apiGen.aliases.filter((alias) => {
507
+ if (ts4.isTypeAliasDeclaration(alias) && alias.type) {
508
+ return ts4.isUnionTypeNode(alias.type);
509
+ }
510
+ return false;
511
+ }).map((alias) => {
512
+ if (ts4.isTypeAliasDeclaration(alias)) {
513
+ return factory.createTypeAliasDeclaration(
514
+ [factory.createModifier(ts4.SyntaxKind.ExportKeyword)],
515
+ alias.name,
516
+ alias.typeParameters,
517
+ alias.type
518
+ );
519
+ }
520
+ return alias;
521
+ });
522
+ const allEnumEntries = [...enumEntries, ...unionTypeEnums];
523
+ if (allEnumEntries.length > 0) {
524
+ allTypeDefinitions.push(
525
+ factory.createModuleDeclaration(
526
+ [factory.createModifier(ts4.SyntaxKind.ExportKeyword)],
527
+ factory.createIdentifier("Enum"),
528
+ factory.createModuleBlock(allEnumEntries),
529
+ ts4.NodeFlags.Namespace
530
+ )
475
531
  );
476
- const fs2 = await import("node:fs/promises");
477
- await fs2.writeFile(sharedTypesFile, output, "utf-8");
478
532
  }
533
+ if (apiGen.aliases.length > 0) {
534
+ const aliasEntries = apiGen.aliases.filter((alias) => {
535
+ if (ts4.isTypeAliasDeclaration(alias)) {
536
+ const isDefinedInComponents = definedTypeNames.has(alias.name.text);
537
+ const isUnionTypeEnum = ts4.isUnionTypeNode(alias.type);
538
+ return !isDefinedInComponents && !isUnionTypeEnum;
539
+ }
540
+ return false;
541
+ }).map((alias) => {
542
+ if (ts4.isTypeAliasDeclaration(alias)) {
543
+ return factory.createTypeAliasDeclaration(
544
+ [factory.createModifier(ts4.SyntaxKind.ExportKeyword)],
545
+ alias.name,
546
+ alias.typeParameters,
547
+ alias.type
548
+ );
549
+ }
550
+ return alias;
551
+ });
552
+ if (aliasEntries.length > 0) {
553
+ const existingSchemeIndex = allTypeDefinitions.findIndex(
554
+ (def) => ts4.isModuleDeclaration(def) && ts4.isIdentifier(def.name) && def.name.text === "Scheme"
555
+ );
556
+ if (existingSchemeIndex >= 0) {
557
+ const existingScheme = allTypeDefinitions[existingSchemeIndex];
558
+ const mergedMembers = [...existingScheme.body.statements, ...aliasEntries];
559
+ allTypeDefinitions[existingSchemeIndex] = factory.createModuleDeclaration(
560
+ [factory.createModifier(ts4.SyntaxKind.ExportKeyword)],
561
+ factory.createIdentifier("Scheme"),
562
+ factory.createModuleBlock(mergedMembers),
563
+ ts4.NodeFlags.Namespace
564
+ );
565
+ } else {
566
+ allTypeDefinitions.push(
567
+ factory.createModuleDeclaration(
568
+ [factory.createModifier(ts4.SyntaxKind.ExportKeyword)],
569
+ factory.createIdentifier("Scheme"),
570
+ factory.createModuleBlock(aliasEntries),
571
+ ts4.NodeFlags.Namespace
572
+ )
573
+ );
574
+ }
575
+ }
576
+ }
577
+ const fs2 = await import("node:fs/promises");
578
+ const path4 = await import("node:path");
579
+ const sharedTypesDir = path4.dirname(sharedTypesFile);
580
+ await fs2.mkdir(sharedTypesDir, { recursive: true });
581
+ const output = printer2.printNode(
582
+ ts4.EmitHint.Unspecified,
583
+ factory.createSourceFile(
584
+ allTypeDefinitions,
585
+ factory.createToken(ts4.SyntaxKind.EndOfFileToken),
586
+ ts4.NodeFlags.None
587
+ ),
588
+ resultFile2
589
+ );
590
+ await fs2.writeFile(sharedTypesFile, output, "utf-8");
479
591
  }
480
592
  if (apiGen.spec.components?.schemas) {
481
593
  apiGen.preprocessComponents(apiGen.spec.components.schemas);
@@ -506,16 +618,13 @@ async function generateApi(spec, {
506
618
  apiFile = apiFile.replace(/\\/g, "/");
507
619
  if (!apiFile.startsWith(".")) apiFile = `./${apiFile}`;
508
620
  }
509
- if (sharedTypesFile && sharedTypesFile.startsWith(".")) {
510
- sharedTypesFile = path2.relative(path2.dirname(outputFile), sharedTypesFile);
511
- sharedTypesFile = sharedTypesFile.replace(/\\/g, "/");
512
- if (!sharedTypesFile.startsWith(".")) sharedTypesFile = `./${sharedTypesFile}`;
513
- }
514
621
  }
515
622
  apiFile = apiFile.replace(/\.[jt]sx?$/, "");
516
- if (sharedTypesFile) {
517
- sharedTypesFile = sharedTypesFile.replace(/\.[jt]sx?$/, "");
518
- }
623
+ const sharedTypesImportPath = sharedTypesFile && outputFile ? (() => {
624
+ let rel = path2.relative(path2.dirname(outputFile), sharedTypesFile).replace(/\\/g, "/").replace(/\.[jt]sx?$/, "");
625
+ if (!rel.startsWith(".")) rel = "./" + rel;
626
+ return rel;
627
+ })() : "./shared-types";
519
628
  return printer.printNode(
520
629
  ts4.EmitHint.Unspecified,
521
630
  factory.createSourceFile(
@@ -523,16 +632,10 @@ async function generateApi(spec, {
523
632
  generateImportNode(apiFile, { [apiImport]: "api" }),
524
633
  generateImportNode("@acrool/react-fetcher", { IRestFulEndpointsQueryReturn: "IRestFulEndpointsQueryReturn" }),
525
634
  ...sharedTypesFile ? [
526
- factory.createImportDeclaration(
527
- void 0,
528
- factory.createImportClause(
529
- false,
530
- void 0,
531
- factory.createNamespaceImport(factory.createIdentifier("SharedTypes"))
532
- ),
533
- factory.createStringLiteral(sharedTypesFile),
534
- void 0
535
- )
635
+ generateImportNode(sharedTypesImportPath, {
636
+ Scheme: "Scheme",
637
+ ...useEnumType ? { Enum: "Enum" } : {}
638
+ })
536
639
  ] : [],
537
640
  ...tag ? [generateTagTypes({ addTagTypes: extractAllTagTypes({ operationDefinitions }) })] : [],
538
641
  generateCreateApiCall({
@@ -541,7 +644,8 @@ async function generateApi(spec, {
541
644
  operationDefinitions.map(
542
645
  (operationDefinition) => generateEndpoint({
543
646
  operationDefinition,
544
- overrides: getOverrides(operationDefinition, endpointOverrides)
647
+ overrides: getOverrides(operationDefinition, endpointOverrides),
648
+ sharedTypesFile: !!sharedTypesFile
545
649
  })
546
650
  ),
547
651
  true
@@ -580,7 +684,8 @@ async function generateApi(spec, {
580
684
  }
581
685
  function generateEndpoint({
582
686
  operationDefinition,
583
- overrides
687
+ overrides,
688
+ sharedTypesFile: sharedTypesFile2
584
689
  }) {
585
690
  const {
586
691
  verb,
@@ -589,60 +694,30 @@ async function generateApi(spec, {
589
694
  operation,
590
695
  operation: { responses, requestBody }
591
696
  } = operationDefinition;
592
- const operationName = getOperationName2({ verb, path: path4, operation });
697
+ const operationName = getOperationName2({ verb, path: path4 });
593
698
  const tags = tag ? getTags({ verb, pathItem }) : [];
594
699
  const isQuery2 = isQuery(verb, overrides);
595
700
  const returnsJson = apiGen.getResponseType(responses) === "json";
596
701
  let ResponseType = factory.createKeywordTypeNode(ts4.SyntaxKind.UnknownKeyword);
597
- function replaceReferences(schema) {
598
- if (!schema) return factory.createKeywordTypeNode(ts4.SyntaxKind.UnknownKeyword);
599
- const refName = getReferenceName(schema);
600
- if (refName && sharedTypesFile) {
601
- return factory.createTypeReferenceNode(
602
- factory.createQualifiedName(
603
- factory.createIdentifier("SharedTypes"),
604
- factory.createIdentifier(refName)
605
- ),
606
- void 0
607
- );
608
- }
609
- if (schema.type === "object" && schema.properties) {
610
- const members = Object.entries(schema.properties).map(([key, value]) => {
611
- return factory.createPropertySignature(
612
- void 0,
613
- factory.createIdentifier(key),
614
- schema.required?.includes(key) ? void 0 : factory.createToken(ts4.SyntaxKind.QuestionToken),
615
- replaceReferences(value)
616
- );
617
- });
618
- return factory.createTypeLiteralNode(members);
619
- }
620
- if (schema.type === "array" && schema.items) {
621
- return factory.createArrayTypeNode(replaceReferences(schema.items));
622
- }
623
- return apiGen.getTypeFromSchema(schema);
624
- }
625
702
  if (returnsJson) {
626
703
  const returnTypes = Object.entries(responses || {}).map(
627
- ([code, response]) => {
628
- const resolvedResponse = apiGen.resolve(response);
629
- if (!resolvedResponse.content?.["application/json"]?.schema) {
630
- return [code, resolvedResponse, factory.createKeywordTypeNode(ts4.SyntaxKind.UndefinedKeyword)];
631
- }
632
- const schema = resolvedResponse.content["application/json"].schema;
633
- const type = replaceReferences(schema);
634
- return [code, resolvedResponse, type];
635
- }
704
+ ([code, response]) => [
705
+ code,
706
+ apiGen.resolve(response),
707
+ wrapWithSchemeIfComponent(
708
+ apiGen.getTypeFromResponse(response, "readOnly") || factory.createKeywordTypeNode(ts4.SyntaxKind.UndefinedKeyword)
709
+ )
710
+ ]
636
711
  ).filter(
637
712
  ([status, response]) => isDataResponse(status, includeDefault, apiGen.resolve(response), responses || {})
638
- ).filter(([_1, _2, type]) => type !== keywordType.void).map(
639
- ([code, response, type]) => ts4.addSyntheticLeadingComment(
640
- { ...type },
713
+ ).filter(([_1, _2, type]) => type !== keywordType.void).map(([code, response, type]) => {
714
+ return ts4.addSyntheticLeadingComment(
715
+ type,
641
716
  ts4.SyntaxKind.MultiLineCommentTrivia,
642
717
  `* status ${code} ${response.description} `,
643
718
  false
644
- )
645
- );
719
+ );
720
+ });
646
721
  if (returnTypes.length > 0) {
647
722
  ResponseType = factory.createUnionTypeNode(returnTypes);
648
723
  }
@@ -677,10 +752,21 @@ async function generateApi(spec, {
677
752
  }
678
753
  return name;
679
754
  }
755
+ for (const param of parameters) {
756
+ const name = generateName(param.name, param.in);
757
+ queryArg[name] = {
758
+ origin: "param",
759
+ name,
760
+ originalName: param.name,
761
+ type: wrapWithSchemeIfComponent(apiGen.getTypeFromSchema(isReference(param) ? param : param.schema, void 0, "writeOnly")),
762
+ required: param.required,
763
+ param
764
+ };
765
+ }
680
766
  if (requestBody) {
681
767
  const body = apiGen.resolve(requestBody);
682
768
  const schema = apiGen.getSchemaFromContent(body.content);
683
- const type = replaceReferences(schema);
769
+ const type = wrapWithSchemeIfComponent(apiGen.getTypeFromSchema(schema));
684
770
  const schemaName = camelCase(
685
771
  type.name || getReferenceName(schema) || typeof schema === "object" && "title" in schema && schema.title || "body"
686
772
  );
@@ -689,24 +775,11 @@ async function generateApi(spec, {
689
775
  origin: "body",
690
776
  name,
691
777
  originalName: schemaName,
692
- type,
778
+ type: wrapWithSchemeIfComponent(apiGen.getTypeFromSchema(schema, void 0, "writeOnly")),
693
779
  required: true,
694
780
  body
695
781
  };
696
782
  }
697
- for (const param of parameters) {
698
- const name = generateName(param.name, param.in);
699
- const paramSchema = isReference(param) ? param : param.schema;
700
- const type = replaceReferences(paramSchema);
701
- queryArg[name] = {
702
- origin: "param",
703
- name,
704
- originalName: param.name,
705
- type,
706
- required: param.required,
707
- param
708
- };
709
- }
710
783
  const propertyName = (name) => {
711
784
  if (typeof name === "string") {
712
785
  return isValidIdentifier(name) ? factory.createIdentifier(name) : factory.createStringLiteral(name);
@@ -843,6 +916,105 @@ async function generateApi(spec, {
843
916
  function generateMutationEndpointProps({}) {
844
917
  return {};
845
918
  }
919
+ function wrapWithSchemeIfComponent(typeNode) {
920
+ if (ts4.isTypeReferenceNode(typeNode) && ts4.isIdentifier(typeNode.typeName)) {
921
+ const typeName = typeNode.typeName.text;
922
+ const isEnumType = useEnumType && (apiGen.enumAliases.some((enumDecl) => {
923
+ if (ts4.isEnumDeclaration(enumDecl) || ts4.isTypeAliasDeclaration(enumDecl)) {
924
+ return enumDecl.name.text === typeName;
925
+ }
926
+ return false;
927
+ }) || apiGen.aliases.some((alias) => {
928
+ if (ts4.isTypeAliasDeclaration(alias) && alias.type) {
929
+ if (ts4.isUnionTypeNode(alias.type)) {
930
+ return alias.name.text === typeName;
931
+ }
932
+ }
933
+ return false;
934
+ }));
935
+ if (isEnumType) {
936
+ return factory.createTypeReferenceNode(
937
+ factory.createQualifiedName(
938
+ factory.createIdentifier("Enum"),
939
+ typeNode.typeName
940
+ ),
941
+ typeNode.typeArguments?.map(wrapWithSchemeIfComponent)
942
+ );
943
+ }
944
+ if (schemeTypeNames.has(typeName)) {
945
+ return factory.createTypeReferenceNode(
946
+ factory.createQualifiedName(
947
+ factory.createIdentifier("Scheme"),
948
+ typeNode.typeName
949
+ ),
950
+ typeNode.typeArguments?.map(wrapWithSchemeIfComponent)
951
+ );
952
+ }
953
+ if (typeNode.typeArguments) {
954
+ return factory.createTypeReferenceNode(
955
+ typeNode.typeName,
956
+ typeNode.typeArguments.map(wrapWithSchemeIfComponent)
957
+ );
958
+ }
959
+ }
960
+ if (ts4.isArrayTypeNode(typeNode)) {
961
+ return factory.createArrayTypeNode(wrapWithSchemeIfComponent(typeNode.elementType));
962
+ }
963
+ if (ts4.isUnionTypeNode(typeNode)) {
964
+ const unionTypes = typeNode.types;
965
+ if (unionTypes.length > 0 && unionTypes.every(
966
+ (type) => ts4.isLiteralTypeNode(type) && (ts4.isStringLiteral(type.literal) || ts4.isNumericLiteral(type.literal))
967
+ )) {
968
+ const enumValues = unionTypes.map((type) => {
969
+ if (ts4.isLiteralTypeNode(type)) {
970
+ if (ts4.isStringLiteral(type.literal)) {
971
+ return type.literal.text;
972
+ } else if (ts4.isNumericLiteral(type.literal)) {
973
+ return type.literal.text;
974
+ }
975
+ }
976
+ return null;
977
+ }).filter(Boolean);
978
+ const matchingEnum = apiGen.aliases.find((alias) => {
979
+ if (ts4.isTypeAliasDeclaration(alias) && ts4.isUnionTypeNode(alias.type)) {
980
+ const aliasValues = alias.type.types.map((type) => {
981
+ if (ts4.isLiteralTypeNode(type)) {
982
+ if (ts4.isStringLiteral(type.literal)) {
983
+ return type.literal.text;
984
+ } else if (ts4.isNumericLiteral(type.literal)) {
985
+ return type.literal.text;
986
+ }
987
+ }
988
+ return null;
989
+ }).filter(Boolean);
990
+ return aliasValues.length === enumValues.length && aliasValues.every((val) => enumValues.includes(val));
991
+ }
992
+ return false;
993
+ });
994
+ if (matchingEnum && ts4.isTypeAliasDeclaration(matchingEnum)) {
995
+ return typeNode;
996
+ }
997
+ }
998
+ return factory.createUnionTypeNode(typeNode.types.map(wrapWithSchemeIfComponent));
999
+ }
1000
+ if (ts4.isTypeLiteralNode(typeNode)) {
1001
+ return factory.createTypeLiteralNode(
1002
+ typeNode.members.map((member) => {
1003
+ if (ts4.isPropertySignature(member) && member.type) {
1004
+ return factory.updatePropertySignature(
1005
+ member,
1006
+ member.modifiers,
1007
+ member.name,
1008
+ member.questionToken,
1009
+ wrapWithSchemeIfComponent(member.type)
1010
+ );
1011
+ }
1012
+ return member;
1013
+ })
1014
+ );
1015
+ }
1016
+ return typeNode;
1017
+ }
846
1018
  }
847
1019
  function generatePathExpression(path4, pathParameters, rootObject, isFlatArg, encodePathParams) {
848
1020
  const expressions = [];
@@ -870,8 +1042,115 @@ function generatePathExpression(path4, pathParameters, rootObject, isFlatArg, en
870
1042
  }
871
1043
 
872
1044
  // src/index.ts
1045
+ import camelCase2 from "lodash.camelcase";
873
1046
  var require2 = createRequire(__filename);
1047
+ async function ensureDirectoryExists(filePath) {
1048
+ const dirname = path3.dirname(filePath);
1049
+ if (!fs.existsSync(dirname)) {
1050
+ await fs.promises.mkdir(dirname, { recursive: true });
1051
+ }
1052
+ }
1053
+ function fileExists(filePath) {
1054
+ try {
1055
+ return fs.statSync(filePath).isFile();
1056
+ } catch {
1057
+ return false;
1058
+ }
1059
+ }
1060
+ function getApiNameFromDir(dirPath) {
1061
+ const dirName = path3.basename(dirPath);
1062
+ return `${dirName}Api`;
1063
+ }
1064
+ async function ensureBaseFilesExist(outputDir) {
1065
+ const enhanceEndpointsPath = path3.join(outputDir, "enhanceEndpoints.ts");
1066
+ const indexPath = path3.join(outputDir, "index.ts");
1067
+ const apiName = getApiNameFromDir(outputDir);
1068
+ if (!fileExists(enhanceEndpointsPath)) {
1069
+ const enhanceEndpointsContent = `import api from './query.generated';
1070
+
1071
+ const enhancedApi = api.enhanceEndpoints({
1072
+ endpoints: {
1073
+ },
1074
+ });
1075
+
1076
+ export default enhancedApi;
1077
+ `;
1078
+ await fs.promises.writeFile(enhanceEndpointsPath, enhanceEndpointsContent, "utf-8");
1079
+ }
1080
+ if (!fileExists(indexPath)) {
1081
+ const indexContent = `export * from './query.generated';
1082
+ export {default as ${apiName}} from './enhanceEndpoints';
1083
+ `;
1084
+ await fs.promises.writeFile(indexPath, indexContent, "utf-8");
1085
+ }
1086
+ }
1087
+ function getGroupNameFromPath(path4, pattern) {
1088
+ const match = path4.match(pattern);
1089
+ if (match && match[1]) {
1090
+ return camelCase2(match[1]);
1091
+ }
1092
+ return "common";
1093
+ }
874
1094
  async function generateEndpoints(options) {
1095
+ const schemaLocation = options.schemaFile;
1096
+ const schemaAbsPath = isValidUrl(options.schemaFile) ? options.schemaFile : path3.resolve(process.cwd(), schemaLocation);
1097
+ if (isValidUrl(options.schemaFile) && "outputFiles" in options) {
1098
+ const { outputFiles, ...commonConfig } = options;
1099
+ const openApiDoc = await getV3Doc(options.schemaFile, options.httpResolverOptions);
1100
+ const paths = Object.keys(openApiDoc.paths);
1101
+ const outputFilesEntries = Object.entries(outputFiles);
1102
+ const [outputPath, config] = outputFilesEntries[0];
1103
+ const patterns = config.groupMatch;
1104
+ const filterEndpoint = config.filterEndpoint;
1105
+ const pattern = patterns;
1106
+ const groupedPaths = paths.reduce((acc, path4) => {
1107
+ const groupName = getGroupNameFromPath(path4, pattern);
1108
+ if (!acc[groupName]) {
1109
+ acc[groupName] = [];
1110
+ }
1111
+ acc[groupName].push(path4);
1112
+ return acc;
1113
+ }, {});
1114
+ for (const [groupName, paths2] of Object.entries(groupedPaths)) {
1115
+ const finalOutputPath = outputPath.replace("$1", groupName);
1116
+ if (filterEndpoint) {
1117
+ const pathBasedFilter = (operationName, operationDefinition) => {
1118
+ const path4 = operationDefinition.path;
1119
+ const pathGroupName = getGroupNameFromPath(path4, pattern);
1120
+ if (pathGroupName !== groupName) {
1121
+ return false;
1122
+ }
1123
+ const endpointFilter = filterEndpoint(groupName);
1124
+ if (endpointFilter instanceof RegExp) {
1125
+ return endpointFilter.test(operationName);
1126
+ }
1127
+ return true;
1128
+ };
1129
+ const groupOptions = {
1130
+ ...commonConfig,
1131
+ outputFile: finalOutputPath,
1132
+ filterEndpoints: pathBasedFilter
1133
+ };
1134
+ await generateSingleEndpoint(groupOptions);
1135
+ } else {
1136
+ const pathBasedFilter = (operationName, operationDefinition) => {
1137
+ const path4 = operationDefinition.path;
1138
+ const pathGroupName = getGroupNameFromPath(path4, pattern);
1139
+ return pathGroupName === groupName;
1140
+ };
1141
+ const groupOptions = {
1142
+ ...commonConfig,
1143
+ outputFile: finalOutputPath,
1144
+ filterEndpoints: pathBasedFilter
1145
+ };
1146
+ await generateSingleEndpoint(groupOptions);
1147
+ }
1148
+ }
1149
+ return;
1150
+ }
1151
+ await generateSingleEndpoint(options);
1152
+ }
1153
+ async function generateSingleEndpoint(options) {
875
1154
  const schemaLocation = options.schemaFile;
876
1155
  const schemaAbsPath = isValidUrl(options.schemaFile) ? options.schemaFile : path3.resolve(process.cwd(), schemaLocation);
877
1156
  const sourceCode = await enforceOazapftsTsVersion(async () => {
@@ -879,8 +1158,12 @@ async function generateEndpoints(options) {
879
1158
  });
880
1159
  const { outputFile, prettierConfigFile } = options;
881
1160
  if (outputFile) {
1161
+ const outputPath = path3.resolve(process.cwd(), outputFile);
1162
+ await ensureDirectoryExists(outputPath);
1163
+ const outputDir = path3.dirname(outputPath);
1164
+ await ensureBaseFilesExist(outputDir);
882
1165
  fs.writeFileSync(
883
- path3.resolve(process.cwd(), outputFile),
1166
+ outputPath,
884
1167
  await prettify(outputFile, sourceCode, prettierConfigFile)
885
1168
  );
886
1169
  } else {
@@ -891,13 +1174,60 @@ function parseConfig(fullConfig) {
891
1174
  const outFiles = [];
892
1175
  if ("outputFiles" in fullConfig) {
893
1176
  const { outputFiles, ...commonConfig } = fullConfig;
894
- for (const [outputFile, specificConfig] of Object.entries(outputFiles)) {
895
- outFiles.push({
896
- ...commonConfig,
897
- ...specificConfig,
898
- outputFile
899
- });
1177
+ let openApiDoc;
1178
+ if (isValidUrl(fullConfig.schemaFile)) {
1179
+ outFiles.push(fullConfig);
1180
+ return outFiles;
1181
+ } else {
1182
+ openApiDoc = JSON.parse(fs.readFileSync(fullConfig.schemaFile, "utf-8"));
900
1183
  }
1184
+ const paths = Object.keys(openApiDoc.paths);
1185
+ const outputFilesEntries = Object.entries(outputFiles);
1186
+ const [outputPath, config] = outputFilesEntries[0];
1187
+ const patterns = config.groupMatch;
1188
+ const filterEndpoint = config.filterEndpoint;
1189
+ const pattern = patterns;
1190
+ const groupedPaths = paths.reduce((acc, path4) => {
1191
+ const groupName = getGroupNameFromPath(path4, pattern);
1192
+ if (!acc[groupName]) {
1193
+ acc[groupName] = [];
1194
+ }
1195
+ acc[groupName].push(path4);
1196
+ return acc;
1197
+ }, {});
1198
+ Object.entries(groupedPaths).forEach(([groupName, paths2]) => {
1199
+ const finalOutputPath = outputPath.replace("$1", groupName);
1200
+ if (filterEndpoint) {
1201
+ const pathBasedFilter = (operationName, operationDefinition) => {
1202
+ const path4 = operationDefinition.path;
1203
+ const pathGroupName = getGroupNameFromPath(path4, pattern);
1204
+ if (pathGroupName !== groupName) {
1205
+ return false;
1206
+ }
1207
+ const endpointFilter = filterEndpoint(groupName);
1208
+ if (endpointFilter instanceof RegExp) {
1209
+ return endpointFilter.test(operationName);
1210
+ }
1211
+ return true;
1212
+ };
1213
+ outFiles.push({
1214
+ ...commonConfig,
1215
+ outputFile: finalOutputPath,
1216
+ filterEndpoints: pathBasedFilter
1217
+ });
1218
+ } else {
1219
+ const pathBasedFilter = (operationName, operationDefinition) => {
1220
+ const path4 = operationDefinition.path;
1221
+ const pathGroupName = getGroupNameFromPath(path4, pattern);
1222
+ return pathGroupName === groupName;
1223
+ };
1224
+ outFiles.push({
1225
+ ...commonConfig,
1226
+ outputFile: finalOutputPath,
1227
+ filterEndpoints: pathBasedFilter
1228
+ });
1229
+ }
1230
+ });
901
1231
  } else {
902
1232
  outFiles.push(fullConfig);
903
1233
  }