ng-openapi 0.1.9 → 0.1.11-pr-20-type-generator-performance-dcd6bb3.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/cli.cjs CHANGED
@@ -24,10 +24,27 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
24
24
  mod
25
25
  ));
26
26
 
27
+ // ../shared/src/utils/functions/is-url.ts
28
+ function isUrl(input) {
29
+ try {
30
+ const url = new URL(input);
31
+ return [
32
+ "http:",
33
+ "https:"
34
+ ].includes(url.protocol);
35
+ } catch {
36
+ return false;
37
+ }
38
+ }
39
+ __name(isUrl, "isUrl");
40
+
27
41
  // src/lib/cli.ts
28
42
  var import_commander = require("commander");
29
- var path11 = __toESM(require("path"));
30
43
  var fs4 = __toESM(require("fs"));
44
+ var path11 = __toESM(require("path"));
45
+
46
+ // package.json
47
+ var version = "0.1.10";
31
48
 
32
49
  // src/lib/core/generator.ts
33
50
  var import_ts_morph6 = require("ts-morph");
@@ -37,12 +54,11 @@ var import_ts_morph = require("ts-morph");
37
54
 
38
55
  // ../shared/src/utils/string.utils.ts
39
56
  function camelCase(str) {
40
- const cleaned = str.replace(/[-_](\w)/g, (_, c) => c.toUpperCase());
41
- return cleaned.charAt(0).toLowerCase() + cleaned.slice(1);
57
+ return str.replace(/[-_\s]+(.)?/g, (_, char) => char ? char.toUpperCase() : "").replace(/^./, (char) => char.toLowerCase());
42
58
  }
43
59
  __name(camelCase, "camelCase");
44
60
  function pascalCase(str) {
45
- return str.replace(/(?:^|[-_])([a-z])/g, (_, char) => char.toUpperCase());
61
+ return str.replace(/[-_\s]+(.)?/g, (_, char) => char ? char.toUpperCase() : "").replace(/^./, (char) => char.toUpperCase());
46
62
  }
47
63
  __name(pascalCase, "pascalCase");
48
64
 
@@ -366,6 +382,12 @@ function inferResponseTypeFromContentType(contentType) {
366
382
  __name(inferResponseTypeFromContentType, "inferResponseTypeFromContentType");
367
383
  function getResponseType(response, config) {
368
384
  const responseType = getResponseTypeFromResponse(response);
385
+ const content = response.content || {};
386
+ for (const [contentType, mediaType] of Object.entries(content)) {
387
+ if (mediaType?.schema) {
388
+ return getTypeScriptType(mediaType.schema, config, mediaType.schema.nullable);
389
+ }
390
+ }
369
391
  switch (responseType) {
370
392
  case "blob":
371
393
  return "Blob";
@@ -373,15 +395,6 @@ function getResponseType(response, config) {
373
395
  return "ArrayBuffer";
374
396
  case "text":
375
397
  return "string";
376
- case "json": {
377
- const content = response.content || {};
378
- for (const [contentType, mediaType] of Object.entries(content)) {
379
- if (inferResponseTypeFromContentType(contentType) === "json" && mediaType?.schema) {
380
- return getTypeScriptType(mediaType.schema, config, mediaType.schema.nullable);
381
- }
382
- }
383
- return "any";
384
- }
385
398
  default:
386
399
  return "any";
387
400
  }
@@ -455,22 +468,6 @@ var BASE_INTERCEPTOR_HEADER_COMMENT = /* @__PURE__ */ __name((clientName) => def
455
468
  var fs = __toESM(require("fs"));
456
469
  var path = __toESM(require("path"));
457
470
  var yaml = __toESM(require("js-yaml"));
458
-
459
- // ../shared/src/utils/functions/is-url.ts
460
- function isUrl(input) {
461
- try {
462
- const url = new URL(input);
463
- return [
464
- "http:",
465
- "https:"
466
- ].includes(url.protocol);
467
- } catch {
468
- return false;
469
- }
470
- }
471
- __name(isUrl, "isUrl");
472
-
473
- // ../shared/src/core/swagger-parser.ts
474
471
  var SwaggerParser = class _SwaggerParser {
475
472
  static {
476
473
  __name(this, "SwaggerParser");
@@ -617,7 +614,7 @@ var SwaggerParser = class _SwaggerParser {
617
614
  };
618
615
 
619
616
  // src/lib/generators/type/type.generator.ts
620
- var TypeGenerator = class _TypeGenerator {
617
+ var TypeGenerator = class {
621
618
  static {
622
619
  __name(this, "TypeGenerator");
623
620
  }
@@ -626,75 +623,67 @@ var TypeGenerator = class _TypeGenerator {
626
623
  sourceFile;
627
624
  generatedTypes = /* @__PURE__ */ new Set();
628
625
  config;
629
- constructor(parser, outputRoot, config) {
626
+ // Performance caches
627
+ pascalCaseCache = /* @__PURE__ */ new Map();
628
+ sanitizedNameCache = /* @__PURE__ */ new Map();
629
+ typeResolutionCache = /* @__PURE__ */ new Map();
630
+ // Batch collection for AST operations
631
+ statements = [];
632
+ deferredTypes = /* @__PURE__ */ new Map();
633
+ constructor(parser, project, config, outputRoot) {
630
634
  this.config = config;
631
- const outputPath = outputRoot + "/models/index.ts";
632
- this.project = new import_ts_morph.Project({
633
- compilerOptions: {
634
- declaration: true,
635
- target: import_ts_morph.ScriptTarget.ES2022,
636
- module: import_ts_morph.ModuleKind.Preserve,
637
- strict: true,
638
- ...this.config.compilerOptions
639
- }
640
- });
635
+ this.project = project;
641
636
  this.parser = parser;
637
+ const outputPath = outputRoot + "/models/index.ts";
642
638
  this.sourceFile = this.project.createSourceFile(outputPath, "", {
643
639
  overwrite: true
644
640
  });
645
641
  }
646
- static async create(swaggerPathOrUrl, outputRoot, config) {
647
- const parser = await SwaggerParser.create(swaggerPathOrUrl, config);
648
- return new _TypeGenerator(parser, outputRoot, config);
649
- }
650
- generate() {
642
+ async generate() {
651
643
  try {
652
644
  const definitions = this.parser.getDefinitions();
653
645
  if (!definitions || Object.keys(definitions).length === 0) {
654
646
  console.warn("No definitions found in swagger file");
655
647
  return;
656
648
  }
657
- this.sourceFile.insertText(0, TYPE_GENERATOR_HEADER_COMMENT);
658
- Object.entries(definitions).forEach(([name, definition]) => {
659
- this.generateInterface(name, definition);
660
- });
661
- this.generateSdkTypes();
662
- this.sourceFile.formatText();
663
- this.sourceFile.saveSync();
649
+ this.collectAllTypeStructures(definitions);
650
+ this.collectSdkTypes();
651
+ this.applyBatchUpdates();
652
+ await this.finalize();
664
653
  } catch (error) {
665
654
  console.error("Error in generate():", error);
666
655
  throw new Error(`Failed to generate types: ${error instanceof Error ? error.message : "Unknown error"}`);
667
656
  }
668
657
  }
669
- generateInterface(name, definition) {
670
- const interfaceName = this.pascalCaseForEnums(name);
671
- if (this.generatedTypes.has(interfaceName)) {
672
- return;
673
- }
674
- this.generatedTypes.add(interfaceName);
658
+ collectAllTypeStructures(definitions) {
659
+ Object.keys(definitions).forEach((name) => {
660
+ const interfaceName = this.getCachedPascalCase(name);
661
+ this.generatedTypes.add(interfaceName);
662
+ });
663
+ Object.entries(definitions).forEach(([name, definition]) => {
664
+ this.collectTypeStructure(name, definition);
665
+ });
666
+ this.deferredTypes.forEach((definition, name) => {
667
+ this.collectTypeStructure(name, definition);
668
+ });
669
+ }
670
+ collectTypeStructure(name, definition) {
671
+ const interfaceName = this.getCachedPascalCase(name) ?? "";
675
672
  if (definition.enum) {
676
- this.generateEnum(interfaceName, definition);
677
- return;
678
- }
679
- if (definition.allOf) {
680
- this.generateCompositeType(interfaceName, definition);
681
- return;
673
+ this.collectEnumStructure(interfaceName, definition);
674
+ } else if (definition.allOf) {
675
+ this.collectCompositeTypeStructure(interfaceName, definition);
676
+ } else {
677
+ this.collectInterfaceStructure(interfaceName, definition);
682
678
  }
683
- const interfaceDeclaration = this.sourceFile.addInterface({
684
- name: interfaceName,
685
- isExported: true,
686
- docs: definition.description ? [
687
- definition.description
688
- ] : void 0
689
- });
690
- this.addInterfaceProperties(interfaceDeclaration, definition);
691
679
  }
692
- generateEnum(name, definition) {
680
+ collectEnumStructure(name, definition) {
693
681
  if (!definition.enum?.length) return;
694
682
  const isStringEnum = definition.enum.some((value) => typeof value === "string");
695
683
  if (isStringEnum) {
696
684
  const unionType = definition.enum.map((value) => typeof value === "string" ? `'${this.escapeString(value)}'` : String(value)).join(" | ");
697
- this.sourceFile.addTypeAlias({
685
+ this.statements.push({
686
+ kind: import_ts_morph.StructureKind.TypeAlias,
698
687
  name,
699
688
  type: unionType,
700
689
  isExported: true,
@@ -702,53 +691,43 @@ var TypeGenerator = class _TypeGenerator {
702
691
  definition.description
703
692
  ] : void 0
704
693
  });
705
- } else if (definition.description && this.config.options.generateEnumBasedOnDescription) {
706
- const enumDeclaration = this.sourceFile.addEnum({
707
- name,
708
- isExported: true
709
- });
710
- try {
711
- const enumValueObjects = JSON.parse(definition.description);
712
- enumValueObjects.forEach((enumValueObject) => {
713
- enumDeclaration.addMember({
714
- name: enumValueObject.Name,
715
- value: enumValueObject.Value
716
- });
717
- });
718
- } catch (e) {
719
- console.error(`Failed to parse enum description for ${name}`);
720
- definition.enum.forEach((value) => {
721
- const enumKey = this.toEnumKey(value);
722
- enumDeclaration.addMember({
723
- name: enumKey,
724
- value
725
- });
726
- });
727
- }
728
694
  } else {
729
- const enumDeclaration = this.sourceFile.addEnum({
695
+ const members = this.buildEnumMembers(definition);
696
+ this.statements.push({
697
+ kind: import_ts_morph.StructureKind.Enum,
730
698
  name,
731
699
  isExported: true,
732
700
  docs: definition.description ? [
733
701
  definition.description
734
- ] : void 0
735
- });
736
- definition.enum.forEach((value) => {
737
- const enumKey = this.toEnumKey(value);
738
- enumDeclaration.addMember({
739
- name: enumKey,
740
- value
741
- });
702
+ ] : void 0,
703
+ members
742
704
  });
743
705
  }
744
706
  }
745
- generateCompositeType(name, definition) {
707
+ buildEnumMembers(definition) {
708
+ if (definition.description && this.config.options.generateEnumBasedOnDescription) {
709
+ try {
710
+ const enumValueObjects = JSON.parse(definition.description);
711
+ return enumValueObjects.map((obj) => ({
712
+ name: obj.Name,
713
+ value: obj.Value
714
+ }));
715
+ } catch {
716
+ }
717
+ }
718
+ return definition.enum?.map((value) => ({
719
+ name: this.toEnumKey(value),
720
+ value
721
+ }));
722
+ }
723
+ collectCompositeTypeStructure(name, definition) {
746
724
  let typeExpression = "";
747
725
  if (definition.allOf) {
748
- const types = definition.allOf.map((def) => this.resolveSwaggerType(def)).filter((type) => type !== "any" && type !== "unknown");
726
+ const types = definition.allOf.map((def) => this.resolveSwaggerTypeCached(def)).filter((type) => type !== "any" && type !== "unknown");
749
727
  typeExpression = types.length > 0 ? types.join(" & ") : "Record<string, unknown>";
750
728
  }
751
- this.sourceFile.addTypeAlias({
729
+ this.statements.push({
730
+ kind: import_ts_morph.StructureKind.TypeAlias,
752
731
  name,
753
732
  type: typeExpression,
754
733
  isExported: true,
@@ -757,33 +736,29 @@ var TypeGenerator = class _TypeGenerator {
757
736
  ] : void 0
758
737
  });
759
738
  }
760
- addInterfaceProperties(interfaceDeclaration, definition) {
761
- if (!definition.properties && definition.additionalProperties === false) {
762
- interfaceDeclaration.addIndexSignature({
763
- keyName: "key",
764
- keyType: "string",
765
- returnType: "never"
766
- });
767
- return;
768
- }
769
- if (!definition.properties && definition.additionalProperties === true) {
770
- interfaceDeclaration.addIndexSignature({
771
- keyName: "key",
772
- keyType: "string",
773
- returnType: "any"
774
- });
775
- return;
776
- }
739
+ collectInterfaceStructure(name, definition) {
740
+ const properties = this.buildInterfaceProperties(definition);
741
+ this.statements.push({
742
+ kind: import_ts_morph.StructureKind.Interface,
743
+ name,
744
+ isExported: true,
745
+ docs: definition.description ? [
746
+ definition.description
747
+ ] : void 0,
748
+ properties,
749
+ indexSignatures: this.buildIndexSignatures(definition)
750
+ });
751
+ }
752
+ buildInterfaceProperties(definition) {
777
753
  if (!definition.properties) {
778
- console.warn(`No properties found for interface ${interfaceDeclaration.getName()}`);
779
- return;
754
+ return [];
780
755
  }
781
- Object.entries(definition.properties).forEach(([propertyName, property]) => {
756
+ return Object.entries(definition.properties).map(([propertyName, property]) => {
782
757
  const isRequired = definition.required?.includes(propertyName) ?? false;
783
758
  const isReadOnly = property.readOnly;
784
- const propertyType = this.resolveSwaggerType(property);
785
- const sanitizedName = this.sanitizePropertyName(propertyName);
786
- interfaceDeclaration.addProperty({
759
+ const propertyType = this.resolveSwaggerTypeCached(property);
760
+ const sanitizedName = this.getCachedSanitizedName(propertyName);
761
+ return {
787
762
  name: sanitizedName,
788
763
  type: propertyType,
789
764
  isReadonly: isReadOnly,
@@ -791,9 +766,48 @@ var TypeGenerator = class _TypeGenerator {
791
766
  docs: property.description ? [
792
767
  property.description
793
768
  ] : void 0
794
- });
769
+ };
795
770
  });
796
771
  }
772
+ buildIndexSignatures(definition) {
773
+ if (!definition.properties && definition.additionalProperties === false) {
774
+ return [
775
+ {
776
+ keyName: "key",
777
+ keyType: "string",
778
+ returnType: "never"
779
+ }
780
+ ];
781
+ }
782
+ if (!definition.properties && definition.additionalProperties === true) {
783
+ return [
784
+ {
785
+ keyName: "key",
786
+ keyType: "string",
787
+ returnType: "any"
788
+ }
789
+ ];
790
+ }
791
+ if (!definition.properties) {
792
+ return [
793
+ {
794
+ keyName: "key",
795
+ keyType: "string",
796
+ returnType: "unknown"
797
+ }
798
+ ];
799
+ }
800
+ return [];
801
+ }
802
+ resolveSwaggerTypeCached(schema) {
803
+ const cacheKey = JSON.stringify(schema);
804
+ if (this.typeResolutionCache.has(cacheKey)) {
805
+ return this.typeResolutionCache.get(cacheKey);
806
+ }
807
+ const result = this.resolveSwaggerType(schema);
808
+ this.typeResolutionCache.set(cacheKey, result);
809
+ return result;
810
+ }
797
811
  resolveSwaggerType(schema) {
798
812
  if (schema.$ref) {
799
813
  return this.resolveReference(schema.$ref);
@@ -802,13 +816,13 @@ var TypeGenerator = class _TypeGenerator {
802
816
  return schema.enum.map((value) => typeof value === "string" ? `'${this.escapeString(value)}'` : String(value)).join(" | ");
803
817
  }
804
818
  if (schema.allOf) {
805
- return schema.allOf.map((def) => this.resolveSwaggerType(def)).filter((type) => type !== "any" && type !== "unknown").join(" & ") || "Record";
819
+ return schema.allOf.map((def) => this.resolveSwaggerTypeCached(def)).filter((type) => type !== "any" && type !== "unknown").join(" & ") || "Record<string, unknown>";
806
820
  }
807
821
  if (schema.oneOf) {
808
- return schema.oneOf.map((def) => this.resolveSwaggerType(def)).filter((type) => type !== "any" && type !== "unknown").join(" | ") || "unknown";
822
+ return schema.oneOf.map((def) => this.resolveSwaggerTypeCached(def)).filter((type) => type !== "any" && type !== "unknown").join(" | ") || "unknown";
809
823
  }
810
824
  if (schema.anyOf) {
811
- return schema.anyOf.map((def) => this.resolveSwaggerType(def)).filter((type) => type !== "any" && type !== "unknown").join(" | ") || "unknown";
825
+ return schema.anyOf.map((def) => this.resolveSwaggerTypeCached(def)).filter((type) => type !== "any" && type !== "unknown").join(" | ") || "unknown";
812
826
  }
813
827
  if (schema.type === "array") {
814
828
  const itemType = schema.items ? this.getArrayItemType(schema.items) : "unknown";
@@ -819,7 +833,7 @@ var TypeGenerator = class _TypeGenerator {
819
833
  return this.generateInlineObjectType(schema);
820
834
  }
821
835
  if (schema.additionalProperties) {
822
- const valueType = typeof schema.additionalProperties === "object" ? this.resolveSwaggerType(schema.additionalProperties) : "unknown";
836
+ const valueType = typeof schema.additionalProperties === "object" ? this.resolveSwaggerTypeCached(schema.additionalProperties) : "unknown";
823
837
  return `Record<string, ${valueType}>`;
824
838
  }
825
839
  return "Record<string, unknown>";
@@ -829,7 +843,7 @@ var TypeGenerator = class _TypeGenerator {
829
843
  generateInlineObjectType(definition) {
830
844
  if (!definition.properties) {
831
845
  if (definition.additionalProperties) {
832
- const additionalType = typeof definition.additionalProperties === "object" ? this.resolveSwaggerType(definition.additionalProperties) : "unknown";
846
+ const additionalType = typeof definition.additionalProperties === "object" ? this.resolveSwaggerTypeCached(definition.additionalProperties) : "unknown";
833
847
  return `Record<string, ${additionalType}>`;
834
848
  }
835
849
  return "Record<string, unknown>";
@@ -837,29 +851,101 @@ var TypeGenerator = class _TypeGenerator {
837
851
  const properties = Object.entries(definition.properties).map(([key, prop]) => {
838
852
  const isRequired = definition.required?.includes(key) ?? false;
839
853
  const questionMark = isRequired ? "" : "?";
840
- const sanitizedKey = this.sanitizePropertyName(key);
841
- return `${sanitizedKey}${questionMark}: ${this.resolveSwaggerType(prop)}`;
854
+ const sanitizedKey = this.getCachedSanitizedName(key);
855
+ return `${sanitizedKey}${questionMark}: ${this.resolveSwaggerTypeCached(prop)}`;
842
856
  }).join("; ");
843
857
  return `{ ${properties} }`;
844
858
  }
845
859
  resolveReference(ref) {
846
- try {
847
- const refDefinition = this.parser.resolveReference(ref);
848
- const refName = ref.split("/").pop();
849
- if (!refName) {
850
- console.warn(`Invalid reference format: ${ref}`);
851
- return "unknown";
860
+ const refName = ref.split("/").pop();
861
+ if (!refName) {
862
+ console.warn(`Invalid reference format: ${ref}`);
863
+ return "unknown";
864
+ }
865
+ return this.getCachedPascalCase(refName);
866
+ }
867
+ collectSdkTypes() {
868
+ const { response } = this.config.options.validation ?? {};
869
+ const typeParameters = [
870
+ "TResponseType extends 'arraybuffer' | 'blob' | 'json' | 'text'"
871
+ ];
872
+ const properties = [
873
+ {
874
+ name: "headers",
875
+ type: "HttpHeaders",
876
+ hasQuestionToken: true
877
+ },
878
+ {
879
+ name: "reportProgress",
880
+ type: "boolean",
881
+ hasQuestionToken: true
882
+ },
883
+ {
884
+ name: "responseType",
885
+ type: "TResponseType",
886
+ hasQuestionToken: true
887
+ },
888
+ {
889
+ name: "withCredentials",
890
+ type: "boolean",
891
+ hasQuestionToken: true
892
+ },
893
+ {
894
+ name: "context",
895
+ type: "HttpContext",
896
+ hasQuestionToken: true
852
897
  }
853
- const typeName = this.pascalCaseForEnums(refName);
854
- if (refDefinition && !this.generatedTypes.has(typeName)) {
855
- this.generateInterface(refName, refDefinition);
898
+ ];
899
+ if (response) {
900
+ properties.push({
901
+ name: "parse",
902
+ type: "(response: unknown) => TReturnType",
903
+ hasQuestionToken: true
904
+ });
905
+ typeParameters.push("TReturnType");
906
+ }
907
+ this.statements.push({
908
+ kind: import_ts_morph.StructureKind.Interface,
909
+ name: "RequestOptions",
910
+ isExported: true,
911
+ typeParameters,
912
+ properties,
913
+ docs: [
914
+ "Request Options for Angular HttpClient requests"
915
+ ]
916
+ });
917
+ }
918
+ applyBatchUpdates() {
919
+ this.sourceFile.insertText(0, TYPE_GENERATOR_HEADER_COMMENT);
920
+ this.sourceFile.addImportDeclarations([
921
+ {
922
+ namedImports: [
923
+ "HttpContext",
924
+ "HttpHeaders"
925
+ ],
926
+ moduleSpecifier: "@angular/common/http"
856
927
  }
857
- return typeName;
858
- } catch (error) {
859
- console.warn(`Failed to resolve reference ${ref}:`, error);
860
- return "unknown";
928
+ ]);
929
+ this.sourceFile.addStatements(this.statements);
930
+ }
931
+ async finalize() {
932
+ this.sourceFile.formatText();
933
+ await this.sourceFile.save();
934
+ }
935
+ // Cached helper methods
936
+ getCachedPascalCase(str) {
937
+ if (!this.pascalCaseCache.has(str)) {
938
+ this.pascalCaseCache.set(str, this.pascalCaseForEnums(str));
861
939
  }
940
+ return this.pascalCaseCache.get(str);
862
941
  }
942
+ getCachedSanitizedName(name) {
943
+ if (!this.sanitizedNameCache.has(name)) {
944
+ this.sanitizedNameCache.set(name, this.sanitizePropertyName(name));
945
+ }
946
+ return this.sanitizedNameCache.get(name);
947
+ }
948
+ // Original helper methods
863
949
  mapSwaggerTypeToTypeScript(type, format, isNullable) {
864
950
  if (!type) return "unknown";
865
951
  switch (type) {
@@ -906,74 +992,15 @@ var TypeGenerator = class _TypeGenerator {
906
992
  }
907
993
  getArrayItemType(items) {
908
994
  if (Array.isArray(items)) {
909
- const types = items.map((item) => this.resolveSwaggerType(item));
995
+ const types = items.map((item) => this.resolveSwaggerTypeCached(item));
910
996
  return `[${types.join(", ")}]`;
911
997
  } else {
912
- return this.resolveSwaggerType(items);
998
+ return this.resolveSwaggerTypeCached(items);
913
999
  }
914
1000
  }
915
1001
  escapeString(str) {
916
1002
  return str.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
917
1003
  }
918
- generateSdkTypes() {
919
- this.sourceFile.addImportDeclarations([
920
- {
921
- namedImports: [
922
- "HttpContext",
923
- "HttpHeaders"
924
- ],
925
- moduleSpecifier: "@angular/common/http"
926
- }
927
- ]);
928
- const { response } = this.config.options.validation ?? {};
929
- const typeParameters = [
930
- "TResponseType extends 'arraybuffer' | 'blob' | 'json' | 'text'"
931
- ];
932
- const properties = [
933
- {
934
- name: "headers",
935
- type: "HttpHeaders",
936
- hasQuestionToken: true
937
- },
938
- {
939
- name: "reportProgress",
940
- type: "boolean",
941
- hasQuestionToken: true
942
- },
943
- {
944
- name: "responseType",
945
- type: "TResponseType",
946
- hasQuestionToken: true
947
- },
948
- {
949
- name: "withCredentials",
950
- type: "boolean",
951
- hasQuestionToken: true
952
- },
953
- {
954
- name: "context",
955
- type: "HttpContext",
956
- hasQuestionToken: true
957
- }
958
- ];
959
- if (response) {
960
- properties.push({
961
- name: "parse",
962
- type: "(response: unknown) => TReturnType",
963
- hasQuestionToken: true
964
- });
965
- typeParameters.push("TReturnType");
966
- }
967
- this.sourceFile.addInterface({
968
- name: "RequestOptions",
969
- isExported: true,
970
- typeParameters,
971
- properties,
972
- docs: [
973
- "Request Options for Angular HttpClient requests"
974
- ]
975
- });
976
- }
977
1004
  };
978
1005
 
979
1006
  // src/lib/generators/utility/token.generator.ts
@@ -2187,7 +2214,10 @@ var ServiceMethodGenerator = class {
2187
2214
  parameters,
2188
2215
  returnType,
2189
2216
  statements: methodBody,
2190
- overloads: methodOverLoads
2217
+ overloads: methodOverLoads,
2218
+ docs: operation.description ? [
2219
+ operation.description
2220
+ ] : void 0
2191
2221
  });
2192
2222
  }
2193
2223
  generateMethodName(operation) {
@@ -2207,15 +2237,17 @@ var ServiceMethodGenerator = class {
2207
2237
  if (operation.operationId) {
2208
2238
  return camelCase(operation.operationId);
2209
2239
  }
2210
- const method = operation.method.toLowerCase();
2211
- const pathParts = operation.path.split("/").filter((p) => p && !p.startsWith("{"));
2212
- const resource = pathParts[pathParts.length - 1] || "resource";
2213
- return `${method}${pascalCase(resource)}`;
2240
+ const method = pascalCase(operation.method.toLowerCase());
2241
+ const pathParts = operation.path.split("/").map((str) => {
2242
+ return pascalCase(pascalCase(str).replace(/[^a-zA-Z0-9]/g, ""));
2243
+ });
2244
+ const resource = pathParts.join("") || "resource";
2245
+ return `${camelCase(resource)}${method}`;
2214
2246
  }
2215
2247
  };
2216
2248
 
2217
2249
  // src/lib/generators/service/service.generator.ts
2218
- var ServiceGenerator = class _ServiceGenerator {
2250
+ var ServiceGenerator = class {
2219
2251
  static {
2220
2252
  __name(this, "ServiceGenerator");
2221
2253
  }
@@ -2235,11 +2267,7 @@ var ServiceGenerator = class _ServiceGenerator {
2235
2267
  }
2236
2268
  this.methodGenerator = new ServiceMethodGenerator(config);
2237
2269
  }
2238
- static async create(swaggerPathOrUrl, project, config) {
2239
- const parser = await SwaggerParser.create(swaggerPathOrUrl, config);
2240
- return new _ServiceGenerator(parser, project, config);
2241
- }
2242
- generate(outputRoot) {
2270
+ async generate(outputRoot) {
2243
2271
  const outputDir = path8.join(outputRoot, "services");
2244
2272
  const paths = extractPaths(this.spec.paths);
2245
2273
  if (paths.length === 0) {
@@ -2247,9 +2275,7 @@ var ServiceGenerator = class _ServiceGenerator {
2247
2275
  return;
2248
2276
  }
2249
2277
  const controllerGroups = this.groupPathsByController(paths);
2250
- Object.entries(controllerGroups).forEach(([controllerName, operations]) => {
2251
- this.generateServiceFile(controllerName, operations, outputDir);
2252
- });
2278
+ await Promise.all(Object.entries(controllerGroups).map(([controllerName, operations]) => this.generateServiceFile(controllerName, operations, outputDir)));
2253
2279
  }
2254
2280
  groupPathsByController(paths) {
2255
2281
  const groups = {};
@@ -2271,7 +2297,7 @@ var ServiceGenerator = class _ServiceGenerator {
2271
2297
  });
2272
2298
  return groups;
2273
2299
  }
2274
- generateServiceFile(controllerName, operations, outputDir) {
2300
+ async generateServiceFile(controllerName, operations, outputDir) {
2275
2301
  const fileName = `${camelCase(controllerName)}.service.ts`;
2276
2302
  const filePath = path8.join(outputDir, fileName);
2277
2303
  const sourceFile = this.project.createSourceFile(filePath, "", {
@@ -2463,8 +2489,9 @@ async function generateFromConfig(config) {
2463
2489
  }
2464
2490
  });
2465
2491
  console.log(`\u{1F4E1} Processing OpenAPI specification from ${inputType}: ${config.input}`);
2466
- const typeGenerator = await TypeGenerator.create(config.input, outputPath, config);
2467
- typeGenerator.generate();
2492
+ const swaggerParser = await SwaggerParser.create(config.input, config);
2493
+ const typeGenerator = new TypeGenerator(swaggerParser, project, config, outputPath);
2494
+ await typeGenerator.generate();
2468
2495
  console.log(`\u2705 TypeScript interfaces generated`);
2469
2496
  if (generateServices) {
2470
2497
  const tokenGenerator = new TokenGenerator(project, config.clientName);
@@ -2475,8 +2502,8 @@ async function generateFromConfig(config) {
2475
2502
  }
2476
2503
  const fileDownloadHelper = new FileDownloadGenerator(project);
2477
2504
  fileDownloadHelper.generate(outputPath);
2478
- const serviceGenerator = await ServiceGenerator.create(config.input, project, config);
2479
- serviceGenerator.generate(outputPath);
2505
+ const serviceGenerator = new ServiceGenerator(swaggerParser, project, config);
2506
+ await serviceGenerator.generate(outputPath);
2480
2507
  const indexGenerator = new ServiceIndexGenerator(project);
2481
2508
  indexGenerator.generateIndex(outputPath);
2482
2509
  console.log(`\u2705 Angular services generated`);
@@ -2487,9 +2514,9 @@ async function generateFromConfig(config) {
2487
2514
  }
2488
2515
  if (config.plugins?.length) {
2489
2516
  for (const plugin of config.plugins) {
2490
- const PluginClass = plugin;
2491
- const pluginGenerator = await PluginClass.create(config.input, project, config);
2492
- pluginGenerator.generate(outputPath);
2517
+ const generatorClass = plugin;
2518
+ const pluginGenerator = new generatorClass(swaggerParser, project, config);
2519
+ await pluginGenerator.generate(outputPath);
2493
2520
  }
2494
2521
  console.log(`\u2705 Plugins are generated`);
2495
2522
  }
@@ -2516,9 +2543,6 @@ async function generateFromConfig(config) {
2516
2543
  }
2517
2544
  __name(generateFromConfig, "generateFromConfig");
2518
2545
 
2519
- // package.json
2520
- var version = "0.1.8";
2521
-
2522
2546
  // src/lib/cli.ts
2523
2547
  var program = new import_commander.Command();
2524
2548
  async function loadConfigFile(configPath) {
@@ -2550,6 +2574,7 @@ async function loadConfigFile(configPath) {
2550
2574
  }
2551
2575
  __name(loadConfigFile, "loadConfigFile");
2552
2576
  async function generateFromOptions(options) {
2577
+ const timestamp = (/* @__PURE__ */ new Date()).getTime();
2553
2578
  try {
2554
2579
  if (options.config) {
2555
2580
  const config = await loadConfigFile(options.config);
@@ -2574,6 +2599,9 @@ async function generateFromOptions(options) {
2574
2599
  console.log("\u2728 Generation completed successfully!");
2575
2600
  } catch (error) {
2576
2601
  console.error("\u274C Generation failed:", error instanceof Error ? error.message : error);
2602
+ } finally {
2603
+ const duration = ((/* @__PURE__ */ new Date()).getTime() - timestamp) / 1e3;
2604
+ console.log(`\u23F1\uFE0F Duration: ${duration.toFixed(2)} seconds`);
2577
2605
  process.exit(1);
2578
2606
  }
2579
2607
  }