ng-openapi 0.1.9 → 0.1.11-beta.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.
Files changed (4) hide show
  1. package/cli.cjs +268 -240
  2. package/index.d.ts +9 -19
  3. package/index.js +276 -243
  4. package/package.json +1 -1
package/index.js CHANGED
@@ -112,16 +112,15 @@ var import_ts_morph = require("ts-morph");
112
112
 
113
113
  // ../shared/src/utils/string.utils.ts
114
114
  function camelCase(str) {
115
- const cleaned = str.replace(/[-_](\w)/g, (_, c) => c.toUpperCase());
116
- return cleaned.charAt(0).toLowerCase() + cleaned.slice(1);
115
+ return str.replace(/[-_\s]+(.)?/g, (_, char) => char ? char.toUpperCase() : "").replace(/^./, (char) => char.toLowerCase());
117
116
  }
118
117
  __name(camelCase, "camelCase");
119
118
  function kebabCase(str) {
120
- return str.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
119
+ return str.replace(/([a-z])([A-Z])/g, "$1-$2").replace(/[-_\s]+/g, "-").toLowerCase();
121
120
  }
122
121
  __name(kebabCase, "kebabCase");
123
122
  function pascalCase(str) {
124
- return str.replace(/(?:^|[-_])([a-z])/g, (_, char) => char.toUpperCase());
123
+ return str.replace(/[-_\s]+(.)?/g, (_, char) => char ? char.toUpperCase() : "").replace(/^./, (char) => char.toUpperCase());
125
124
  }
126
125
  __name(pascalCase, "pascalCase");
127
126
 
@@ -447,6 +446,12 @@ function inferResponseTypeFromContentType(contentType) {
447
446
  __name(inferResponseTypeFromContentType, "inferResponseTypeFromContentType");
448
447
  function getResponseType(response, config) {
449
448
  const responseType = getResponseTypeFromResponse(response);
449
+ const content = response.content || {};
450
+ for (const [contentType, mediaType] of Object.entries(content)) {
451
+ if (mediaType == null ? void 0 : mediaType.schema) {
452
+ return getTypeScriptType(mediaType.schema, config, mediaType.schema.nullable);
453
+ }
454
+ }
450
455
  switch (responseType) {
451
456
  case "blob":
452
457
  return "Blob";
@@ -454,15 +459,6 @@ function getResponseType(response, config) {
454
459
  return "ArrayBuffer";
455
460
  case "text":
456
461
  return "string";
457
- case "json": {
458
- const content = response.content || {};
459
- for (const [contentType, mediaType] of Object.entries(content)) {
460
- if (inferResponseTypeFromContentType(contentType) === "json" && (mediaType == null ? void 0 : mediaType.schema)) {
461
- return getTypeScriptType(mediaType.schema, config, mediaType.schema.nullable);
462
- }
463
- }
464
- return "any";
465
- }
466
462
  default:
467
463
  return "any";
468
464
  }
@@ -724,82 +720,76 @@ var SwaggerParser = _SwaggerParser;
724
720
 
725
721
  // src/lib/generators/type/type.generator.ts
726
722
  var _TypeGenerator = class _TypeGenerator {
727
- constructor(parser, outputRoot, config) {
723
+ constructor(parser, project, config, outputRoot) {
728
724
  __publicField(this, "project");
729
725
  __publicField(this, "parser");
730
726
  __publicField(this, "sourceFile");
731
727
  __publicField(this, "generatedTypes", /* @__PURE__ */ new Set());
732
728
  __publicField(this, "config");
729
+ // Performance caches
730
+ __publicField(this, "pascalCaseCache", /* @__PURE__ */ new Map());
731
+ __publicField(this, "sanitizedNameCache", /* @__PURE__ */ new Map());
732
+ __publicField(this, "typeResolutionCache", /* @__PURE__ */ new Map());
733
+ // Batch collection for AST operations
734
+ __publicField(this, "statements", []);
735
+ __publicField(this, "deferredTypes", /* @__PURE__ */ new Map());
733
736
  this.config = config;
734
- const outputPath = outputRoot + "/models/index.ts";
735
- this.project = new import_ts_morph.Project({
736
- compilerOptions: __spreadValues({
737
- declaration: true,
738
- target: import_ts_morph.ScriptTarget.ES2022,
739
- module: import_ts_morph.ModuleKind.Preserve,
740
- strict: true
741
- }, this.config.compilerOptions)
742
- });
737
+ this.project = project;
743
738
  this.parser = parser;
739
+ const outputPath = outputRoot + "/models/index.ts";
744
740
  this.sourceFile = this.project.createSourceFile(outputPath, "", {
745
741
  overwrite: true
746
742
  });
747
743
  }
748
- static create(swaggerPathOrUrl, outputRoot, config) {
744
+ generate() {
749
745
  return __async(this, null, function* () {
750
- const parser = yield SwaggerParser.create(swaggerPathOrUrl, config);
751
- return new _TypeGenerator(parser, outputRoot, config);
746
+ try {
747
+ const definitions = this.parser.getDefinitions();
748
+ if (!definitions || Object.keys(definitions).length === 0) {
749
+ console.warn("No definitions found in swagger file");
750
+ return;
751
+ }
752
+ this.collectAllTypeStructures(definitions);
753
+ this.collectSdkTypes();
754
+ this.applyBatchUpdates();
755
+ yield this.finalize();
756
+ } catch (error) {
757
+ console.error("Error in generate():", error);
758
+ throw new Error(`Failed to generate types: ${error instanceof Error ? error.message : "Unknown error"}`);
759
+ }
752
760
  });
753
761
  }
754
- generate() {
755
- try {
756
- const definitions = this.parser.getDefinitions();
757
- if (!definitions || Object.keys(definitions).length === 0) {
758
- console.warn("No definitions found in swagger file");
759
- return;
760
- }
761
- this.sourceFile.insertText(0, TYPE_GENERATOR_HEADER_COMMENT);
762
- Object.entries(definitions).forEach(([name, definition]) => {
763
- this.generateInterface(name, definition);
764
- });
765
- this.generateSdkTypes();
766
- this.sourceFile.formatText();
767
- this.sourceFile.saveSync();
768
- } catch (error) {
769
- console.error("Error in generate():", error);
770
- throw new Error(`Failed to generate types: ${error instanceof Error ? error.message : "Unknown error"}`);
771
- }
762
+ collectAllTypeStructures(definitions) {
763
+ Object.keys(definitions).forEach((name) => {
764
+ const interfaceName = this.getCachedPascalCase(name);
765
+ this.generatedTypes.add(interfaceName);
766
+ });
767
+ Object.entries(definitions).forEach(([name, definition]) => {
768
+ this.collectTypeStructure(name, definition);
769
+ });
770
+ this.deferredTypes.forEach((definition, name) => {
771
+ this.collectTypeStructure(name, definition);
772
+ });
772
773
  }
773
- generateInterface(name, definition) {
774
- const interfaceName = this.pascalCaseForEnums(name);
775
- if (this.generatedTypes.has(interfaceName)) {
776
- return;
777
- }
778
- this.generatedTypes.add(interfaceName);
774
+ collectTypeStructure(name, definition) {
775
+ var _a;
776
+ const interfaceName = (_a = this.getCachedPascalCase(name)) != null ? _a : "";
779
777
  if (definition.enum) {
780
- this.generateEnum(interfaceName, definition);
781
- return;
782
- }
783
- if (definition.allOf) {
784
- this.generateCompositeType(interfaceName, definition);
785
- return;
778
+ this.collectEnumStructure(interfaceName, definition);
779
+ } else if (definition.allOf) {
780
+ this.collectCompositeTypeStructure(interfaceName, definition);
781
+ } else {
782
+ this.collectInterfaceStructure(interfaceName, definition);
786
783
  }
787
- const interfaceDeclaration = this.sourceFile.addInterface({
788
- name: interfaceName,
789
- isExported: true,
790
- docs: definition.description ? [
791
- definition.description
792
- ] : void 0
793
- });
794
- this.addInterfaceProperties(interfaceDeclaration, definition);
795
784
  }
796
- generateEnum(name, definition) {
785
+ collectEnumStructure(name, definition) {
797
786
  var _a;
798
787
  if (!((_a = definition.enum) == null ? void 0 : _a.length)) return;
799
788
  const isStringEnum = definition.enum.some((value) => typeof value === "string");
800
789
  if (isStringEnum) {
801
790
  const unionType = definition.enum.map((value) => typeof value === "string" ? `'${this.escapeString(value)}'` : String(value)).join(" | ");
802
- this.sourceFile.addTypeAlias({
791
+ this.statements.push({
792
+ kind: import_ts_morph.StructureKind.TypeAlias,
803
793
  name,
804
794
  type: unionType,
805
795
  isExported: true,
@@ -807,53 +797,44 @@ var _TypeGenerator = class _TypeGenerator {
807
797
  definition.description
808
798
  ] : void 0
809
799
  });
810
- } else if (definition.description && this.config.options.generateEnumBasedOnDescription) {
811
- const enumDeclaration = this.sourceFile.addEnum({
812
- name,
813
- isExported: true
814
- });
815
- try {
816
- const enumValueObjects = JSON.parse(definition.description);
817
- enumValueObjects.forEach((enumValueObject) => {
818
- enumDeclaration.addMember({
819
- name: enumValueObject.Name,
820
- value: enumValueObject.Value
821
- });
822
- });
823
- } catch (e) {
824
- console.error(`Failed to parse enum description for ${name}`);
825
- definition.enum.forEach((value) => {
826
- const enumKey = this.toEnumKey(value);
827
- enumDeclaration.addMember({
828
- name: enumKey,
829
- value
830
- });
831
- });
832
- }
833
800
  } else {
834
- const enumDeclaration = this.sourceFile.addEnum({
801
+ const members = this.buildEnumMembers(definition);
802
+ this.statements.push({
803
+ kind: import_ts_morph.StructureKind.Enum,
835
804
  name,
836
805
  isExported: true,
837
806
  docs: definition.description ? [
838
807
  definition.description
839
- ] : void 0
840
- });
841
- definition.enum.forEach((value) => {
842
- const enumKey = this.toEnumKey(value);
843
- enumDeclaration.addMember({
844
- name: enumKey,
845
- value
846
- });
808
+ ] : void 0,
809
+ members
847
810
  });
848
811
  }
849
812
  }
850
- generateCompositeType(name, definition) {
813
+ buildEnumMembers(definition) {
814
+ var _a;
815
+ if (definition.description && this.config.options.generateEnumBasedOnDescription) {
816
+ try {
817
+ const enumValueObjects = JSON.parse(definition.description);
818
+ return enumValueObjects.map((obj) => ({
819
+ name: obj.Name,
820
+ value: obj.Value
821
+ }));
822
+ } catch (e) {
823
+ }
824
+ }
825
+ return (_a = definition.enum) == null ? void 0 : _a.map((value) => ({
826
+ name: this.toEnumKey(value),
827
+ value
828
+ }));
829
+ }
830
+ collectCompositeTypeStructure(name, definition) {
851
831
  let typeExpression = "";
852
832
  if (definition.allOf) {
853
- const types = definition.allOf.map((def) => this.resolveSwaggerType(def)).filter((type) => type !== "any" && type !== "unknown");
833
+ const types = definition.allOf.map((def) => this.resolveSwaggerTypeCached(def)).filter((type) => type !== "any" && type !== "unknown");
854
834
  typeExpression = types.length > 0 ? types.join(" & ") : "Record<string, unknown>";
855
835
  }
856
- this.sourceFile.addTypeAlias({
836
+ this.statements.push({
837
+ kind: import_ts_morph.StructureKind.TypeAlias,
857
838
  name,
858
839
  type: typeExpression,
859
840
  isExported: true,
@@ -862,34 +843,30 @@ var _TypeGenerator = class _TypeGenerator {
862
843
  ] : void 0
863
844
  });
864
845
  }
865
- addInterfaceProperties(interfaceDeclaration, definition) {
866
- if (!definition.properties && definition.additionalProperties === false) {
867
- interfaceDeclaration.addIndexSignature({
868
- keyName: "key",
869
- keyType: "string",
870
- returnType: "never"
871
- });
872
- return;
873
- }
874
- if (!definition.properties && definition.additionalProperties === true) {
875
- interfaceDeclaration.addIndexSignature({
876
- keyName: "key",
877
- keyType: "string",
878
- returnType: "any"
879
- });
880
- return;
881
- }
846
+ collectInterfaceStructure(name, definition) {
847
+ const properties = this.buildInterfaceProperties(definition);
848
+ this.statements.push({
849
+ kind: import_ts_morph.StructureKind.Interface,
850
+ name,
851
+ isExported: true,
852
+ docs: definition.description ? [
853
+ definition.description
854
+ ] : void 0,
855
+ properties,
856
+ indexSignatures: this.buildIndexSignatures(definition)
857
+ });
858
+ }
859
+ buildInterfaceProperties(definition) {
882
860
  if (!definition.properties) {
883
- console.warn(`No properties found for interface ${interfaceDeclaration.getName()}`);
884
- return;
861
+ return [];
885
862
  }
886
- Object.entries(definition.properties).forEach(([propertyName, property]) => {
863
+ return Object.entries(definition.properties).map(([propertyName, property]) => {
887
864
  var _a, _b;
888
865
  const isRequired = (_b = (_a = definition.required) == null ? void 0 : _a.includes(propertyName)) != null ? _b : false;
889
866
  const isReadOnly = property.readOnly;
890
- const propertyType = this.resolveSwaggerType(property);
891
- const sanitizedName = this.sanitizePropertyName(propertyName);
892
- interfaceDeclaration.addProperty({
867
+ const propertyType = this.resolveSwaggerTypeCached(property);
868
+ const sanitizedName = this.getCachedSanitizedName(propertyName);
869
+ return {
893
870
  name: sanitizedName,
894
871
  type: propertyType,
895
872
  isReadonly: isReadOnly,
@@ -897,9 +874,48 @@ var _TypeGenerator = class _TypeGenerator {
897
874
  docs: property.description ? [
898
875
  property.description
899
876
  ] : void 0
900
- });
877
+ };
901
878
  });
902
879
  }
880
+ buildIndexSignatures(definition) {
881
+ if (!definition.properties && definition.additionalProperties === false) {
882
+ return [
883
+ {
884
+ keyName: "key",
885
+ keyType: "string",
886
+ returnType: "never"
887
+ }
888
+ ];
889
+ }
890
+ if (!definition.properties && definition.additionalProperties === true) {
891
+ return [
892
+ {
893
+ keyName: "key",
894
+ keyType: "string",
895
+ returnType: "any"
896
+ }
897
+ ];
898
+ }
899
+ if (!definition.properties) {
900
+ return [
901
+ {
902
+ keyName: "key",
903
+ keyType: "string",
904
+ returnType: "unknown"
905
+ }
906
+ ];
907
+ }
908
+ return [];
909
+ }
910
+ resolveSwaggerTypeCached(schema) {
911
+ const cacheKey = JSON.stringify(schema);
912
+ if (this.typeResolutionCache.has(cacheKey)) {
913
+ return this.typeResolutionCache.get(cacheKey);
914
+ }
915
+ const result = this.resolveSwaggerType(schema);
916
+ this.typeResolutionCache.set(cacheKey, result);
917
+ return result;
918
+ }
903
919
  resolveSwaggerType(schema) {
904
920
  if (schema.$ref) {
905
921
  return this.resolveReference(schema.$ref);
@@ -908,13 +924,13 @@ var _TypeGenerator = class _TypeGenerator {
908
924
  return schema.enum.map((value) => typeof value === "string" ? `'${this.escapeString(value)}'` : String(value)).join(" | ");
909
925
  }
910
926
  if (schema.allOf) {
911
- return schema.allOf.map((def) => this.resolveSwaggerType(def)).filter((type) => type !== "any" && type !== "unknown").join(" & ") || "Record";
927
+ return schema.allOf.map((def) => this.resolveSwaggerTypeCached(def)).filter((type) => type !== "any" && type !== "unknown").join(" & ") || "Record<string, unknown>";
912
928
  }
913
929
  if (schema.oneOf) {
914
- return schema.oneOf.map((def) => this.resolveSwaggerType(def)).filter((type) => type !== "any" && type !== "unknown").join(" | ") || "unknown";
930
+ return schema.oneOf.map((def) => this.resolveSwaggerTypeCached(def)).filter((type) => type !== "any" && type !== "unknown").join(" | ") || "unknown";
915
931
  }
916
932
  if (schema.anyOf) {
917
- return schema.anyOf.map((def) => this.resolveSwaggerType(def)).filter((type) => type !== "any" && type !== "unknown").join(" | ") || "unknown";
933
+ return schema.anyOf.map((def) => this.resolveSwaggerTypeCached(def)).filter((type) => type !== "any" && type !== "unknown").join(" | ") || "unknown";
918
934
  }
919
935
  if (schema.type === "array") {
920
936
  const itemType = schema.items ? this.getArrayItemType(schema.items) : "unknown";
@@ -925,7 +941,7 @@ var _TypeGenerator = class _TypeGenerator {
925
941
  return this.generateInlineObjectType(schema);
926
942
  }
927
943
  if (schema.additionalProperties) {
928
- const valueType = typeof schema.additionalProperties === "object" ? this.resolveSwaggerType(schema.additionalProperties) : "unknown";
944
+ const valueType = typeof schema.additionalProperties === "object" ? this.resolveSwaggerTypeCached(schema.additionalProperties) : "unknown";
929
945
  return `Record<string, ${valueType}>`;
930
946
  }
931
947
  return "Record<string, unknown>";
@@ -935,7 +951,7 @@ var _TypeGenerator = class _TypeGenerator {
935
951
  generateInlineObjectType(definition) {
936
952
  if (!definition.properties) {
937
953
  if (definition.additionalProperties) {
938
- const additionalType = typeof definition.additionalProperties === "object" ? this.resolveSwaggerType(definition.additionalProperties) : "unknown";
954
+ const additionalType = typeof definition.additionalProperties === "object" ? this.resolveSwaggerTypeCached(definition.additionalProperties) : "unknown";
939
955
  return `Record<string, ${additionalType}>`;
940
956
  }
941
957
  return "Record<string, unknown>";
@@ -944,29 +960,104 @@ var _TypeGenerator = class _TypeGenerator {
944
960
  var _a, _b;
945
961
  const isRequired = (_b = (_a = definition.required) == null ? void 0 : _a.includes(key)) != null ? _b : false;
946
962
  const questionMark = isRequired ? "" : "?";
947
- const sanitizedKey = this.sanitizePropertyName(key);
948
- return `${sanitizedKey}${questionMark}: ${this.resolveSwaggerType(prop)}`;
963
+ const sanitizedKey = this.getCachedSanitizedName(key);
964
+ return `${sanitizedKey}${questionMark}: ${this.resolveSwaggerTypeCached(prop)}`;
949
965
  }).join("; ");
950
966
  return `{ ${properties} }`;
951
967
  }
952
968
  resolveReference(ref) {
953
- try {
954
- const refDefinition = this.parser.resolveReference(ref);
955
- const refName = ref.split("/").pop();
956
- if (!refName) {
957
- console.warn(`Invalid reference format: ${ref}`);
958
- return "unknown";
969
+ const refName = ref.split("/").pop();
970
+ if (!refName) {
971
+ console.warn(`Invalid reference format: ${ref}`);
972
+ return "unknown";
973
+ }
974
+ return this.getCachedPascalCase(refName);
975
+ }
976
+ collectSdkTypes() {
977
+ var _a;
978
+ const { response } = (_a = this.config.options.validation) != null ? _a : {};
979
+ const typeParameters = [
980
+ "TResponseType extends 'arraybuffer' | 'blob' | 'json' | 'text'"
981
+ ];
982
+ const properties = [
983
+ {
984
+ name: "headers",
985
+ type: "HttpHeaders",
986
+ hasQuestionToken: true
987
+ },
988
+ {
989
+ name: "reportProgress",
990
+ type: "boolean",
991
+ hasQuestionToken: true
992
+ },
993
+ {
994
+ name: "responseType",
995
+ type: "TResponseType",
996
+ hasQuestionToken: true
997
+ },
998
+ {
999
+ name: "withCredentials",
1000
+ type: "boolean",
1001
+ hasQuestionToken: true
1002
+ },
1003
+ {
1004
+ name: "context",
1005
+ type: "HttpContext",
1006
+ hasQuestionToken: true
959
1007
  }
960
- const typeName = this.pascalCaseForEnums(refName);
961
- if (refDefinition && !this.generatedTypes.has(typeName)) {
962
- this.generateInterface(refName, refDefinition);
1008
+ ];
1009
+ if (response) {
1010
+ properties.push({
1011
+ name: "parse",
1012
+ type: "(response: unknown) => TReturnType",
1013
+ hasQuestionToken: true
1014
+ });
1015
+ typeParameters.push("TReturnType");
1016
+ }
1017
+ this.statements.push({
1018
+ kind: import_ts_morph.StructureKind.Interface,
1019
+ name: "RequestOptions",
1020
+ isExported: true,
1021
+ typeParameters,
1022
+ properties,
1023
+ docs: [
1024
+ "Request Options for Angular HttpClient requests"
1025
+ ]
1026
+ });
1027
+ }
1028
+ applyBatchUpdates() {
1029
+ this.sourceFile.insertText(0, TYPE_GENERATOR_HEADER_COMMENT);
1030
+ this.sourceFile.addImportDeclarations([
1031
+ {
1032
+ namedImports: [
1033
+ "HttpContext",
1034
+ "HttpHeaders"
1035
+ ],
1036
+ moduleSpecifier: "@angular/common/http"
963
1037
  }
964
- return typeName;
965
- } catch (error) {
966
- console.warn(`Failed to resolve reference ${ref}:`, error);
967
- return "unknown";
1038
+ ]);
1039
+ this.sourceFile.addStatements(this.statements);
1040
+ }
1041
+ finalize() {
1042
+ return __async(this, null, function* () {
1043
+ this.sourceFile.formatText();
1044
+ yield this.sourceFile.save();
1045
+ });
1046
+ }
1047
+ // Cached helper methods
1048
+ getCachedPascalCase(str) {
1049
+ if (!this.pascalCaseCache.has(str)) {
1050
+ this.pascalCaseCache.set(str, this.pascalCaseForEnums(str));
968
1051
  }
1052
+ return this.pascalCaseCache.get(str);
969
1053
  }
1054
+ getCachedSanitizedName(name) {
1055
+ if (!this.sanitizedNameCache.has(name)) {
1056
+ this.sanitizedNameCache.set(name, this.sanitizePropertyName(name));
1057
+ }
1058
+ return this.sanitizedNameCache.get(name);
1059
+ }
1060
+ // Original helper methods
970
1061
  mapSwaggerTypeToTypeScript(type, format, isNullable) {
971
1062
  if (!type) return "unknown";
972
1063
  switch (type) {
@@ -1013,75 +1104,15 @@ var _TypeGenerator = class _TypeGenerator {
1013
1104
  }
1014
1105
  getArrayItemType(items) {
1015
1106
  if (Array.isArray(items)) {
1016
- const types = items.map((item) => this.resolveSwaggerType(item));
1107
+ const types = items.map((item) => this.resolveSwaggerTypeCached(item));
1017
1108
  return `[${types.join(", ")}]`;
1018
1109
  } else {
1019
- return this.resolveSwaggerType(items);
1110
+ return this.resolveSwaggerTypeCached(items);
1020
1111
  }
1021
1112
  }
1022
1113
  escapeString(str) {
1023
1114
  return str.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
1024
1115
  }
1025
- generateSdkTypes() {
1026
- var _a;
1027
- this.sourceFile.addImportDeclarations([
1028
- {
1029
- namedImports: [
1030
- "HttpContext",
1031
- "HttpHeaders"
1032
- ],
1033
- moduleSpecifier: "@angular/common/http"
1034
- }
1035
- ]);
1036
- const { response } = (_a = this.config.options.validation) != null ? _a : {};
1037
- const typeParameters = [
1038
- "TResponseType extends 'arraybuffer' | 'blob' | 'json' | 'text'"
1039
- ];
1040
- const properties = [
1041
- {
1042
- name: "headers",
1043
- type: "HttpHeaders",
1044
- hasQuestionToken: true
1045
- },
1046
- {
1047
- name: "reportProgress",
1048
- type: "boolean",
1049
- hasQuestionToken: true
1050
- },
1051
- {
1052
- name: "responseType",
1053
- type: "TResponseType",
1054
- hasQuestionToken: true
1055
- },
1056
- {
1057
- name: "withCredentials",
1058
- type: "boolean",
1059
- hasQuestionToken: true
1060
- },
1061
- {
1062
- name: "context",
1063
- type: "HttpContext",
1064
- hasQuestionToken: true
1065
- }
1066
- ];
1067
- if (response) {
1068
- properties.push({
1069
- name: "parse",
1070
- type: "(response: unknown) => TReturnType",
1071
- hasQuestionToken: true
1072
- });
1073
- typeParameters.push("TReturnType");
1074
- }
1075
- this.sourceFile.addInterface({
1076
- name: "RequestOptions",
1077
- isExported: true,
1078
- typeParameters,
1079
- properties,
1080
- docs: [
1081
- "Request Options for Angular HttpClient requests"
1082
- ]
1083
- });
1084
- }
1085
1116
  };
1086
1117
  __name(_TypeGenerator, "TypeGenerator");
1087
1118
  var TypeGenerator = _TypeGenerator;
@@ -2299,7 +2330,10 @@ var _ServiceMethodGenerator = class _ServiceMethodGenerator {
2299
2330
  parameters,
2300
2331
  returnType,
2301
2332
  statements: methodBody,
2302
- overloads: methodOverLoads
2333
+ overloads: methodOverLoads,
2334
+ docs: operation.description ? [
2335
+ operation.description
2336
+ ] : void 0
2303
2337
  });
2304
2338
  }
2305
2339
  generateMethodName(operation) {
@@ -2319,10 +2353,12 @@ var _ServiceMethodGenerator = class _ServiceMethodGenerator {
2319
2353
  if (operation.operationId) {
2320
2354
  return camelCase(operation.operationId);
2321
2355
  }
2322
- const method = operation.method.toLowerCase();
2323
- const pathParts = operation.path.split("/").filter((p) => p && !p.startsWith("{"));
2324
- const resource = pathParts[pathParts.length - 1] || "resource";
2325
- return `${method}${pascalCase(resource)}`;
2356
+ const method = pascalCase(operation.method.toLowerCase());
2357
+ const pathParts = operation.path.split("/").map((str) => {
2358
+ return pascalCase(pascalCase(str).replace(/[^a-zA-Z0-9]/g, ""));
2359
+ });
2360
+ const resource = pathParts.join("") || "resource";
2361
+ return `${camelCase(resource)}${method}`;
2326
2362
  }
2327
2363
  };
2328
2364
  __name(_ServiceMethodGenerator, "ServiceMethodGenerator");
@@ -2346,22 +2382,16 @@ var _ServiceGenerator = class _ServiceGenerator {
2346
2382
  }
2347
2383
  this.methodGenerator = new ServiceMethodGenerator(config);
2348
2384
  }
2349
- static create(swaggerPathOrUrl, project, config) {
2350
- return __async(this, null, function* () {
2351
- const parser = yield SwaggerParser.create(swaggerPathOrUrl, config);
2352
- return new _ServiceGenerator(parser, project, config);
2353
- });
2354
- }
2355
2385
  generate(outputRoot) {
2356
- const outputDir = path8.join(outputRoot, "services");
2357
- const paths = extractPaths(this.spec.paths);
2358
- if (paths.length === 0) {
2359
- console.warn("No API paths found in the specification");
2360
- return;
2361
- }
2362
- const controllerGroups = this.groupPathsByController(paths);
2363
- Object.entries(controllerGroups).forEach(([controllerName, operations]) => {
2364
- this.generateServiceFile(controllerName, operations, outputDir);
2386
+ return __async(this, null, function* () {
2387
+ const outputDir = path8.join(outputRoot, "services");
2388
+ const paths = extractPaths(this.spec.paths);
2389
+ if (paths.length === 0) {
2390
+ console.warn("No API paths found in the specification");
2391
+ return;
2392
+ }
2393
+ const controllerGroups = this.groupPathsByController(paths);
2394
+ yield Promise.all(Object.entries(controllerGroups).map(([controllerName, operations]) => this.generateServiceFile(controllerName, operations, outputDir)));
2365
2395
  });
2366
2396
  }
2367
2397
  groupPathsByController(paths) {
@@ -2385,16 +2415,18 @@ var _ServiceGenerator = class _ServiceGenerator {
2385
2415
  return groups;
2386
2416
  }
2387
2417
  generateServiceFile(controllerName, operations, outputDir) {
2388
- const fileName = `${camelCase(controllerName)}.service.ts`;
2389
- const filePath = path8.join(outputDir, fileName);
2390
- const sourceFile = this.project.createSourceFile(filePath, "", {
2391
- overwrite: true
2418
+ return __async(this, null, function* () {
2419
+ const fileName = `${camelCase(controllerName)}.service.ts`;
2420
+ const filePath = path8.join(outputDir, fileName);
2421
+ const sourceFile = this.project.createSourceFile(filePath, "", {
2422
+ overwrite: true
2423
+ });
2424
+ const usedTypes = collectUsedTypes(operations);
2425
+ this.addImports(sourceFile, usedTypes);
2426
+ this.addServiceClass(sourceFile, controllerName, operations);
2427
+ sourceFile.formatText();
2428
+ sourceFile.saveSync();
2392
2429
  });
2393
- const usedTypes = collectUsedTypes(operations);
2394
- this.addImports(sourceFile, usedTypes);
2395
- this.addServiceClass(sourceFile, controllerName, operations);
2396
- sourceFile.formatText();
2397
- sourceFile.saveSync();
2398
2430
  }
2399
2431
  addImports(sourceFile, usedTypes) {
2400
2432
  const basePathTokenName = getBasePathTokenName(this.config.clientName);
@@ -2578,8 +2610,9 @@ function generateFromConfig(config) {
2578
2610
  }, config.compilerOptions)
2579
2611
  });
2580
2612
  console.log(`\u{1F4E1} Processing OpenAPI specification from ${inputType}: ${config.input}`);
2581
- const typeGenerator = yield TypeGenerator.create(config.input, outputPath, config);
2582
- typeGenerator.generate();
2613
+ const swaggerParser = yield SwaggerParser.create(config.input, config);
2614
+ const typeGenerator = new TypeGenerator(swaggerParser, project, config, outputPath);
2615
+ yield typeGenerator.generate();
2583
2616
  console.log(`\u2705 TypeScript interfaces generated`);
2584
2617
  if (generateServices) {
2585
2618
  const tokenGenerator = new TokenGenerator(project, config.clientName);
@@ -2590,8 +2623,8 @@ function generateFromConfig(config) {
2590
2623
  }
2591
2624
  const fileDownloadHelper = new FileDownloadGenerator(project);
2592
2625
  fileDownloadHelper.generate(outputPath);
2593
- const serviceGenerator = yield ServiceGenerator.create(config.input, project, config);
2594
- serviceGenerator.generate(outputPath);
2626
+ const serviceGenerator = new ServiceGenerator(swaggerParser, project, config);
2627
+ yield serviceGenerator.generate(outputPath);
2595
2628
  const indexGenerator = new ServiceIndexGenerator(project);
2596
2629
  indexGenerator.generateIndex(outputPath);
2597
2630
  console.log(`\u2705 Angular services generated`);
@@ -2602,9 +2635,9 @@ function generateFromConfig(config) {
2602
2635
  }
2603
2636
  if ((_b = config.plugins) == null ? void 0 : _b.length) {
2604
2637
  for (const plugin of config.plugins) {
2605
- const PluginClass = plugin;
2606
- const pluginGenerator = yield PluginClass.create(config.input, project, config);
2607
- pluginGenerator.generate(outputPath);
2638
+ const generatorClass = plugin;
2639
+ const pluginGenerator = new generatorClass(swaggerParser, project, config);
2640
+ yield pluginGenerator.generate(outputPath);
2608
2641
  }
2609
2642
  console.log(`\u2705 Plugins are generated`);
2610
2643
  }