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

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,154 @@ 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
+ if (components.schemas) {
465
+ const typeEntries = Object.entries(components.schemas).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
  });
466
- });
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
477
+ allTypeDefinitions.push(
478
+ factory.createModuleDeclaration(
479
+ [factory.createModifier(ts4.SyntaxKind.ExportKeyword)],
480
+ factory.createIdentifier("Scheme"),
481
+ factory.createModuleBlock(typeEntries),
482
+ ts4.NodeFlags.Namespace
483
+ )
484
+ );
485
+ }
486
+ }
487
+ const enumEntries = [
488
+ ...apiGen.enumAliases.filter((e) => ts4.isEnumDeclaration(e)),
489
+ ...apiGen.enumAliases.filter((e) => ts4.isTypeAliasDeclaration(e))
490
+ ].map((enumDecl) => {
491
+ if (ts4.isEnumDeclaration(enumDecl)) {
492
+ return factory.createEnumDeclaration(
493
+ [factory.createModifier(ts4.SyntaxKind.ExportKeyword)],
494
+ enumDecl.name,
495
+ enumDecl.members
496
+ );
497
+ } else if (ts4.isTypeAliasDeclaration(enumDecl)) {
498
+ return factory.createTypeAliasDeclaration(
499
+ [factory.createModifier(ts4.SyntaxKind.ExportKeyword)],
500
+ enumDecl.name,
501
+ enumDecl.typeParameters,
502
+ enumDecl.type
503
+ );
504
+ }
505
+ return enumDecl;
506
+ });
507
+ const unionTypeEnums = apiGen.aliases.filter((alias) => {
508
+ if (ts4.isTypeAliasDeclaration(alias) && alias.type) {
509
+ return ts4.isUnionTypeNode(alias.type);
510
+ }
511
+ return false;
512
+ }).map((alias) => {
513
+ if (ts4.isTypeAliasDeclaration(alias)) {
514
+ return factory.createTypeAliasDeclaration(
515
+ [factory.createModifier(ts4.SyntaxKind.ExportKeyword)],
516
+ alias.name,
517
+ alias.typeParameters,
518
+ alias.type
519
+ );
520
+ }
521
+ return alias;
522
+ });
523
+ const allEnumEntries = [...enumEntries, ...unionTypeEnums];
524
+ if (allEnumEntries.length > 0) {
525
+ allTypeDefinitions.push(
526
+ factory.createModuleDeclaration(
527
+ [factory.createModifier(ts4.SyntaxKind.ExportKeyword)],
528
+ factory.createIdentifier("Enum"),
529
+ factory.createModuleBlock(allEnumEntries),
530
+ ts4.NodeFlags.Namespace
531
+ )
475
532
  );
476
- const fs2 = await import("node:fs/promises");
477
- await fs2.writeFile(sharedTypesFile, output, "utf-8");
478
533
  }
534
+ if (apiGen.aliases.length > 0) {
535
+ const aliasEntries = apiGen.aliases.filter((alias) => {
536
+ if (ts4.isTypeAliasDeclaration(alias)) {
537
+ const isDefinedInComponents = definedTypeNames.has(alias.name.text);
538
+ const isUnionTypeEnum = ts4.isUnionTypeNode(alias.type);
539
+ return !isDefinedInComponents && !isUnionTypeEnum;
540
+ }
541
+ return false;
542
+ }).map((alias) => {
543
+ if (ts4.isTypeAliasDeclaration(alias)) {
544
+ return factory.createTypeAliasDeclaration(
545
+ [factory.createModifier(ts4.SyntaxKind.ExportKeyword)],
546
+ alias.name,
547
+ alias.typeParameters,
548
+ alias.type
549
+ );
550
+ }
551
+ return alias;
552
+ });
553
+ if (aliasEntries.length > 0) {
554
+ const existingSchemeIndex = allTypeDefinitions.findIndex(
555
+ (def) => ts4.isModuleDeclaration(def) && ts4.isIdentifier(def.name) && def.name.text === "Scheme"
556
+ );
557
+ if (existingSchemeIndex >= 0) {
558
+ const existingScheme = allTypeDefinitions[existingSchemeIndex];
559
+ const mergedMembers = [...existingScheme.body.statements, ...aliasEntries];
560
+ allTypeDefinitions[existingSchemeIndex] = factory.createModuleDeclaration(
561
+ [factory.createModifier(ts4.SyntaxKind.ExportKeyword)],
562
+ factory.createIdentifier("Scheme"),
563
+ factory.createModuleBlock(mergedMembers),
564
+ ts4.NodeFlags.Namespace
565
+ );
566
+ } else {
567
+ allTypeDefinitions.push(
568
+ factory.createModuleDeclaration(
569
+ [factory.createModifier(ts4.SyntaxKind.ExportKeyword)],
570
+ factory.createIdentifier("Scheme"),
571
+ factory.createModuleBlock(aliasEntries),
572
+ ts4.NodeFlags.Namespace
573
+ )
574
+ );
575
+ }
576
+ }
577
+ }
578
+ const fs2 = await import("node:fs/promises");
579
+ const path4 = await import("node:path");
580
+ const sharedTypesDir = path4.dirname(sharedTypesFile);
581
+ await fs2.mkdir(sharedTypesDir, { recursive: true });
582
+ const output = printer2.printNode(
583
+ ts4.EmitHint.Unspecified,
584
+ factory.createSourceFile(
585
+ allTypeDefinitions,
586
+ factory.createToken(ts4.SyntaxKind.EndOfFileToken),
587
+ ts4.NodeFlags.None
588
+ ),
589
+ resultFile2
590
+ );
591
+ await fs2.writeFile(sharedTypesFile, output, "utf-8");
479
592
  }
480
593
  if (apiGen.spec.components?.schemas) {
481
594
  apiGen.preprocessComponents(apiGen.spec.components.schemas);
@@ -506,16 +619,13 @@ async function generateApi(spec, {
506
619
  apiFile = apiFile.replace(/\\/g, "/");
507
620
  if (!apiFile.startsWith(".")) apiFile = `./${apiFile}`;
508
621
  }
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
622
  }
515
623
  apiFile = apiFile.replace(/\.[jt]sx?$/, "");
516
- if (sharedTypesFile) {
517
- sharedTypesFile = sharedTypesFile.replace(/\.[jt]sx?$/, "");
518
- }
624
+ const sharedTypesImportPath = sharedTypesFile && outputFile ? (() => {
625
+ let rel = path2.relative(path2.dirname(outputFile), sharedTypesFile).replace(/\\/g, "/").replace(/\.[jt]sx?$/, "");
626
+ if (!rel.startsWith(".")) rel = "./" + rel;
627
+ return rel;
628
+ })() : "./shared-types";
519
629
  return printer.printNode(
520
630
  ts4.EmitHint.Unspecified,
521
631
  factory.createSourceFile(
@@ -523,16 +633,10 @@ async function generateApi(spec, {
523
633
  generateImportNode(apiFile, { [apiImport]: "api" }),
524
634
  generateImportNode("@acrool/react-fetcher", { IRestFulEndpointsQueryReturn: "IRestFulEndpointsQueryReturn" }),
525
635
  ...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
- )
636
+ generateImportNode(sharedTypesImportPath, {
637
+ Scheme: "Scheme",
638
+ ...useEnumType ? { Enum: "Enum" } : {}
639
+ })
536
640
  ] : [],
537
641
  ...tag ? [generateTagTypes({ addTagTypes: extractAllTagTypes({ operationDefinitions }) })] : [],
538
642
  generateCreateApiCall({
@@ -541,17 +645,14 @@ async function generateApi(spec, {
541
645
  operationDefinitions.map(
542
646
  (operationDefinition) => generateEndpoint({
543
647
  operationDefinition,
544
- overrides: getOverrides(operationDefinition, endpointOverrides)
648
+ overrides: getOverrides(operationDefinition, endpointOverrides),
649
+ sharedTypesFile: !!sharedTypesFile
545
650
  })
546
651
  ),
547
652
  true
548
653
  )
549
654
  }),
550
- factory.createExportAssignment(
551
- void 0,
552
- void 0,
553
- factory.createIdentifier(generatedApiName)
554
- ),
655
+ factory.createExportAssignment(void 0, void 0, factory.createIdentifier(generatedApiName)),
555
656
  ...Object.values(interfaces),
556
657
  ...sharedTypesFile ? [] : [...apiGen.aliases, ...apiGen.enumAliases],
557
658
  ...hooks ? [
@@ -580,7 +681,8 @@ async function generateApi(spec, {
580
681
  }
581
682
  function generateEndpoint({
582
683
  operationDefinition,
583
- overrides
684
+ overrides,
685
+ sharedTypesFile: sharedTypesFile2
584
686
  }) {
585
687
  const {
586
688
  verb,
@@ -589,60 +691,30 @@ async function generateApi(spec, {
589
691
  operation,
590
692
  operation: { responses, requestBody }
591
693
  } = operationDefinition;
592
- const operationName = getOperationName2({ verb, path: path4, operation });
694
+ const operationName = getOperationName2({ verb, path: path4 });
593
695
  const tags = tag ? getTags({ verb, pathItem }) : [];
594
696
  const isQuery2 = isQuery(verb, overrides);
595
697
  const returnsJson = apiGen.getResponseType(responses) === "json";
596
698
  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
699
  if (returnsJson) {
626
700
  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
- }
701
+ ([code, response]) => [
702
+ code,
703
+ apiGen.resolve(response),
704
+ wrapWithSchemeIfComponent(
705
+ apiGen.getTypeFromResponse(response, "readOnly") || factory.createKeywordTypeNode(ts4.SyntaxKind.UndefinedKeyword)
706
+ )
707
+ ]
636
708
  ).filter(
637
709
  ([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 },
710
+ ).filter(([_1, _2, type]) => type !== keywordType.void).map(([code, response, type]) => {
711
+ return ts4.addSyntheticLeadingComment(
712
+ type,
641
713
  ts4.SyntaxKind.MultiLineCommentTrivia,
642
714
  `* status ${code} ${response.description} `,
643
715
  false
644
- )
645
- );
716
+ );
717
+ });
646
718
  if (returnTypes.length > 0) {
647
719
  ResponseType = factory.createUnionTypeNode(returnTypes);
648
720
  }
@@ -677,10 +749,23 @@ async function generateApi(spec, {
677
749
  }
678
750
  return name;
679
751
  }
752
+ for (const param of parameters) {
753
+ const name = generateName(param.name, param.in);
754
+ queryArg[name] = {
755
+ origin: "param",
756
+ name,
757
+ originalName: param.name,
758
+ type: wrapWithSchemeIfComponent(
759
+ apiGen.getTypeFromSchema(isReference(param) ? param : param.schema, void 0, "writeOnly")
760
+ ),
761
+ required: param.required,
762
+ param
763
+ };
764
+ }
680
765
  if (requestBody) {
681
766
  const body = apiGen.resolve(requestBody);
682
767
  const schema = apiGen.getSchemaFromContent(body.content);
683
- const type = replaceReferences(schema);
768
+ const type = wrapWithSchemeIfComponent(apiGen.getTypeFromSchema(schema));
684
769
  const schemaName = camelCase(
685
770
  type.name || getReferenceName(schema) || typeof schema === "object" && "title" in schema && schema.title || "body"
686
771
  );
@@ -689,24 +774,11 @@ async function generateApi(spec, {
689
774
  origin: "body",
690
775
  name,
691
776
  originalName: schemaName,
692
- type,
777
+ type: wrapWithSchemeIfComponent(apiGen.getTypeFromSchema(schema, void 0, "writeOnly")),
693
778
  required: true,
694
779
  body
695
780
  };
696
781
  }
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
782
  const propertyName = (name) => {
711
783
  if (typeof name === "string") {
712
784
  return isValidIdentifier(name) ? factory.createIdentifier(name) : factory.createStringLiteral(name);
@@ -749,10 +821,7 @@ async function generateApi(spec, {
749
821
  operationName: operationNameSuffix ? capitalize(operationName + operationNameSuffix) : operationName,
750
822
  type: isQuery2 ? "query" : "mutation",
751
823
  Response: ResponseTypeName,
752
- QueryArg: factory.createTypeReferenceNode(
753
- factory.createIdentifier("IRestFulEndpointsQueryReturn"),
754
- [QueryArg]
755
- ),
824
+ QueryArg: factory.createTypeReferenceNode(factory.createIdentifier("IRestFulEndpointsQueryReturn"), [QueryArg]),
756
825
  queryFn: generateQueryFn({
757
826
  operationDefinition,
758
827
  queryArg,
@@ -773,10 +842,18 @@ async function generateApi(spec, {
773
842
  encodePathParams: encodePathParams2,
774
843
  encodeQueryParams: encodeQueryParams2
775
844
  }) {
776
- const { path: path4, verb } = operationDefinition;
845
+ const { path: path4, verb, operation } = operationDefinition;
777
846
  const bodyParameter = Object.values(queryArg).find((def) => def.origin === "body");
778
847
  const rootObject = factory.createIdentifier("queryArg");
779
848
  const variablesObject = factory.createPropertyAccessExpression(rootObject, factory.createIdentifier("variables"));
849
+ function getContentType() {
850
+ if (operation.requestBody) {
851
+ const requestBody = apiGen.resolve(operation.requestBody);
852
+ const contentTypes = Object.keys(requestBody.content || {});
853
+ return contentTypes[0];
854
+ }
855
+ return void 0;
856
+ }
780
857
  function pickParams(paramIn) {
781
858
  return Object.values(queryArg).filter((def) => def.origin === "param" && def.param.in === paramIn);
782
859
  }
@@ -800,6 +877,7 @@ async function generateApi(spec, {
800
877
  factory.createObjectLiteralExpression(properties, true)
801
878
  );
802
879
  }
880
+ const contentType = getContentType();
803
881
  return factory.createArrowFunction(
804
882
  void 0,
805
883
  void 0,
@@ -817,9 +895,16 @@ async function generateApi(spec, {
817
895
  factory.createIdentifier("method"),
818
896
  factory.createStringLiteral(verb.toUpperCase())
819
897
  ),
898
+ contentType ? factory.createPropertyAssignment(
899
+ factory.createIdentifier("contentType"),
900
+ factory.createStringLiteral(contentType)
901
+ ) : void 0,
820
902
  bodyParameter === void 0 ? void 0 : factory.createPropertyAssignment(
821
903
  factory.createIdentifier("body"),
822
- isFlatArg ? variablesObject : factory.createPropertyAccessExpression(variablesObject, factory.createIdentifier(bodyParameter.name))
904
+ isFlatArg ? variablesObject : factory.createPropertyAccessExpression(
905
+ variablesObject,
906
+ factory.createIdentifier(bodyParameter.name)
907
+ )
823
908
  ),
824
909
  createObjectLiteralProperty(pickParams("cookie"), "cookies"),
825
910
  createObjectLiteralProperty(pickParams("query"), "params"),
@@ -843,6 +928,99 @@ async function generateApi(spec, {
843
928
  function generateMutationEndpointProps({}) {
844
929
  return {};
845
930
  }
931
+ function wrapWithSchemeIfComponent(typeNode) {
932
+ if (ts4.isTypeReferenceNode(typeNode) && ts4.isIdentifier(typeNode.typeName)) {
933
+ const typeName = typeNode.typeName.text;
934
+ const isEnumType = useEnumType && (apiGen.enumAliases.some((enumDecl) => {
935
+ if (ts4.isEnumDeclaration(enumDecl) || ts4.isTypeAliasDeclaration(enumDecl)) {
936
+ return enumDecl.name.text === typeName;
937
+ }
938
+ return false;
939
+ }) || apiGen.aliases.some((alias) => {
940
+ if (ts4.isTypeAliasDeclaration(alias) && alias.type) {
941
+ if (ts4.isUnionTypeNode(alias.type)) {
942
+ return alias.name.text === typeName;
943
+ }
944
+ }
945
+ return false;
946
+ }));
947
+ if (isEnumType) {
948
+ return factory.createTypeReferenceNode(
949
+ factory.createQualifiedName(factory.createIdentifier("Enum"), typeNode.typeName),
950
+ typeNode.typeArguments?.map(wrapWithSchemeIfComponent)
951
+ );
952
+ }
953
+ if (schemeTypeNames.has(typeName)) {
954
+ return factory.createTypeReferenceNode(
955
+ factory.createQualifiedName(factory.createIdentifier("Scheme"), typeNode.typeName),
956
+ typeNode.typeArguments?.map(wrapWithSchemeIfComponent)
957
+ );
958
+ }
959
+ if (typeNode.typeArguments) {
960
+ return factory.createTypeReferenceNode(
961
+ typeNode.typeName,
962
+ typeNode.typeArguments.map(wrapWithSchemeIfComponent)
963
+ );
964
+ }
965
+ }
966
+ if (ts4.isArrayTypeNode(typeNode)) {
967
+ return factory.createArrayTypeNode(wrapWithSchemeIfComponent(typeNode.elementType));
968
+ }
969
+ if (ts4.isUnionTypeNode(typeNode)) {
970
+ const unionTypes = typeNode.types;
971
+ if (unionTypes.length > 0 && unionTypes.every(
972
+ (type) => ts4.isLiteralTypeNode(type) && (ts4.isStringLiteral(type.literal) || ts4.isNumericLiteral(type.literal))
973
+ )) {
974
+ const enumValues = unionTypes.map((type) => {
975
+ if (ts4.isLiteralTypeNode(type)) {
976
+ if (ts4.isStringLiteral(type.literal)) {
977
+ return type.literal.text;
978
+ } else if (ts4.isNumericLiteral(type.literal)) {
979
+ return type.literal.text;
980
+ }
981
+ }
982
+ return null;
983
+ }).filter(Boolean);
984
+ const matchingEnum = apiGen.aliases.find((alias) => {
985
+ if (ts4.isTypeAliasDeclaration(alias) && ts4.isUnionTypeNode(alias.type)) {
986
+ const aliasValues = alias.type.types.map((type) => {
987
+ if (ts4.isLiteralTypeNode(type)) {
988
+ if (ts4.isStringLiteral(type.literal)) {
989
+ return type.literal.text;
990
+ } else if (ts4.isNumericLiteral(type.literal)) {
991
+ return type.literal.text;
992
+ }
993
+ }
994
+ return null;
995
+ }).filter(Boolean);
996
+ return aliasValues.length === enumValues.length && aliasValues.every((val) => enumValues.includes(val));
997
+ }
998
+ return false;
999
+ });
1000
+ if (matchingEnum && ts4.isTypeAliasDeclaration(matchingEnum)) {
1001
+ return typeNode;
1002
+ }
1003
+ }
1004
+ return factory.createUnionTypeNode(typeNode.types.map(wrapWithSchemeIfComponent));
1005
+ }
1006
+ if (ts4.isTypeLiteralNode(typeNode)) {
1007
+ return factory.createTypeLiteralNode(
1008
+ typeNode.members.map((member) => {
1009
+ if (ts4.isPropertySignature(member) && member.type) {
1010
+ return factory.updatePropertySignature(
1011
+ member,
1012
+ member.modifiers,
1013
+ member.name,
1014
+ member.questionToken,
1015
+ wrapWithSchemeIfComponent(member.type)
1016
+ );
1017
+ }
1018
+ return member;
1019
+ })
1020
+ );
1021
+ }
1022
+ return typeNode;
1023
+ }
846
1024
  }
847
1025
  function generatePathExpression(path4, pathParameters, rootObject, isFlatArg, encodePathParams) {
848
1026
  const expressions = [];
@@ -870,8 +1048,115 @@ function generatePathExpression(path4, pathParameters, rootObject, isFlatArg, en
870
1048
  }
871
1049
 
872
1050
  // src/index.ts
1051
+ import camelCase2 from "lodash.camelcase";
873
1052
  var require2 = createRequire(__filename);
1053
+ async function ensureDirectoryExists(filePath) {
1054
+ const dirname = path3.dirname(filePath);
1055
+ if (!fs.existsSync(dirname)) {
1056
+ await fs.promises.mkdir(dirname, { recursive: true });
1057
+ }
1058
+ }
1059
+ function fileExists(filePath) {
1060
+ try {
1061
+ return fs.statSync(filePath).isFile();
1062
+ } catch {
1063
+ return false;
1064
+ }
1065
+ }
1066
+ function getApiNameFromDir(dirPath) {
1067
+ const dirName = path3.basename(dirPath);
1068
+ return `${dirName}Api`;
1069
+ }
1070
+ async function ensureBaseFilesExist(outputDir) {
1071
+ const enhanceEndpointsPath = path3.join(outputDir, "enhanceEndpoints.ts");
1072
+ const indexPath = path3.join(outputDir, "index.ts");
1073
+ const apiName = getApiNameFromDir(outputDir);
1074
+ if (!fileExists(enhanceEndpointsPath)) {
1075
+ const enhanceEndpointsContent = `import api from './query.generated';
1076
+
1077
+ const enhancedApi = api.enhanceEndpoints({
1078
+ endpoints: {
1079
+ },
1080
+ });
1081
+
1082
+ export default enhancedApi;
1083
+ `;
1084
+ await fs.promises.writeFile(enhanceEndpointsPath, enhanceEndpointsContent, "utf-8");
1085
+ }
1086
+ if (!fileExists(indexPath)) {
1087
+ const indexContent = `export * from './query.generated';
1088
+ export {default as ${apiName}} from './enhanceEndpoints';
1089
+ `;
1090
+ await fs.promises.writeFile(indexPath, indexContent, "utf-8");
1091
+ }
1092
+ }
1093
+ function getGroupNameFromPath(path4, pattern) {
1094
+ const match = path4.match(pattern);
1095
+ if (match && match[1]) {
1096
+ return camelCase2(match[1]);
1097
+ }
1098
+ return "common";
1099
+ }
874
1100
  async function generateEndpoints(options) {
1101
+ const schemaLocation = options.schemaFile;
1102
+ const schemaAbsPath = isValidUrl(options.schemaFile) ? options.schemaFile : path3.resolve(process.cwd(), schemaLocation);
1103
+ if (isValidUrl(options.schemaFile) && "outputFiles" in options) {
1104
+ const { outputFiles, ...commonConfig } = options;
1105
+ const openApiDoc = await getV3Doc(options.schemaFile, options.httpResolverOptions);
1106
+ const paths = Object.keys(openApiDoc.paths);
1107
+ const outputFilesEntries = Object.entries(outputFiles);
1108
+ const [outputPath, config] = outputFilesEntries[0];
1109
+ const patterns = config.groupMatch;
1110
+ const filterEndpoint = config.filterEndpoint;
1111
+ const pattern = patterns;
1112
+ const groupedPaths = paths.reduce((acc, path4) => {
1113
+ const groupName = getGroupNameFromPath(path4, pattern);
1114
+ if (!acc[groupName]) {
1115
+ acc[groupName] = [];
1116
+ }
1117
+ acc[groupName].push(path4);
1118
+ return acc;
1119
+ }, {});
1120
+ for (const [groupName, paths2] of Object.entries(groupedPaths)) {
1121
+ const finalOutputPath = outputPath.replace("$1", groupName);
1122
+ if (filterEndpoint) {
1123
+ const pathBasedFilter = (operationName, operationDefinition) => {
1124
+ const path4 = operationDefinition.path;
1125
+ const pathGroupName = getGroupNameFromPath(path4, pattern);
1126
+ if (pathGroupName !== groupName) {
1127
+ return false;
1128
+ }
1129
+ const endpointFilter = filterEndpoint(groupName);
1130
+ if (endpointFilter instanceof RegExp) {
1131
+ return endpointFilter.test(operationName);
1132
+ }
1133
+ return true;
1134
+ };
1135
+ const groupOptions = {
1136
+ ...commonConfig,
1137
+ outputFile: finalOutputPath,
1138
+ filterEndpoints: pathBasedFilter
1139
+ };
1140
+ await generateSingleEndpoint(groupOptions);
1141
+ } else {
1142
+ const pathBasedFilter = (operationName, operationDefinition) => {
1143
+ const path4 = operationDefinition.path;
1144
+ const pathGroupName = getGroupNameFromPath(path4, pattern);
1145
+ return pathGroupName === groupName;
1146
+ };
1147
+ const groupOptions = {
1148
+ ...commonConfig,
1149
+ outputFile: finalOutputPath,
1150
+ filterEndpoints: pathBasedFilter
1151
+ };
1152
+ await generateSingleEndpoint(groupOptions);
1153
+ }
1154
+ }
1155
+ return;
1156
+ }
1157
+ await generateSingleEndpoint(options);
1158
+ }
1159
+ async function generateSingleEndpoint(options) {
875
1160
  const schemaLocation = options.schemaFile;
876
1161
  const schemaAbsPath = isValidUrl(options.schemaFile) ? options.schemaFile : path3.resolve(process.cwd(), schemaLocation);
877
1162
  const sourceCode = await enforceOazapftsTsVersion(async () => {
@@ -879,8 +1164,12 @@ async function generateEndpoints(options) {
879
1164
  });
880
1165
  const { outputFile, prettierConfigFile } = options;
881
1166
  if (outputFile) {
1167
+ const outputPath = path3.resolve(process.cwd(), outputFile);
1168
+ await ensureDirectoryExists(outputPath);
1169
+ const outputDir = path3.dirname(outputPath);
1170
+ await ensureBaseFilesExist(outputDir);
882
1171
  fs.writeFileSync(
883
- path3.resolve(process.cwd(), outputFile),
1172
+ outputPath,
884
1173
  await prettify(outputFile, sourceCode, prettierConfigFile)
885
1174
  );
886
1175
  } else {
@@ -891,13 +1180,60 @@ function parseConfig(fullConfig) {
891
1180
  const outFiles = [];
892
1181
  if ("outputFiles" in fullConfig) {
893
1182
  const { outputFiles, ...commonConfig } = fullConfig;
894
- for (const [outputFile, specificConfig] of Object.entries(outputFiles)) {
895
- outFiles.push({
896
- ...commonConfig,
897
- ...specificConfig,
898
- outputFile
899
- });
1183
+ let openApiDoc;
1184
+ if (isValidUrl(fullConfig.schemaFile)) {
1185
+ outFiles.push(fullConfig);
1186
+ return outFiles;
1187
+ } else {
1188
+ openApiDoc = JSON.parse(fs.readFileSync(fullConfig.schemaFile, "utf-8"));
900
1189
  }
1190
+ const paths = Object.keys(openApiDoc.paths);
1191
+ const outputFilesEntries = Object.entries(outputFiles);
1192
+ const [outputPath, config] = outputFilesEntries[0];
1193
+ const patterns = config.groupMatch;
1194
+ const filterEndpoint = config.filterEndpoint;
1195
+ const pattern = patterns;
1196
+ const groupedPaths = paths.reduce((acc, path4) => {
1197
+ const groupName = getGroupNameFromPath(path4, pattern);
1198
+ if (!acc[groupName]) {
1199
+ acc[groupName] = [];
1200
+ }
1201
+ acc[groupName].push(path4);
1202
+ return acc;
1203
+ }, {});
1204
+ Object.entries(groupedPaths).forEach(([groupName, paths2]) => {
1205
+ const finalOutputPath = outputPath.replace("$1", groupName);
1206
+ if (filterEndpoint) {
1207
+ const pathBasedFilter = (operationName, operationDefinition) => {
1208
+ const path4 = operationDefinition.path;
1209
+ const pathGroupName = getGroupNameFromPath(path4, pattern);
1210
+ if (pathGroupName !== groupName) {
1211
+ return false;
1212
+ }
1213
+ const endpointFilter = filterEndpoint(groupName);
1214
+ if (endpointFilter instanceof RegExp) {
1215
+ return endpointFilter.test(operationName);
1216
+ }
1217
+ return true;
1218
+ };
1219
+ outFiles.push({
1220
+ ...commonConfig,
1221
+ outputFile: finalOutputPath,
1222
+ filterEndpoints: pathBasedFilter
1223
+ });
1224
+ } else {
1225
+ const pathBasedFilter = (operationName, operationDefinition) => {
1226
+ const path4 = operationDefinition.path;
1227
+ const pathGroupName = getGroupNameFromPath(path4, pattern);
1228
+ return pathGroupName === groupName;
1229
+ };
1230
+ outFiles.push({
1231
+ ...commonConfig,
1232
+ outputFile: finalOutputPath,
1233
+ filterEndpoints: pathBasedFilter
1234
+ });
1235
+ }
1236
+ });
901
1237
  } else {
902
1238
  outFiles.push(fullConfig);
903
1239
  }