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.
- package/cli.cjs +268 -240
- package/index.d.ts +9 -19
- package/index.js +276 -243
- 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
|
-
|
|
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(/
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
658
|
-
|
|
659
|
-
|
|
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
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
}
|
|
674
|
-
|
|
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.
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
this.
|
|
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
|
-
|
|
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.
|
|
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
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
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
|
-
|
|
779
|
-
return;
|
|
754
|
+
return [];
|
|
780
755
|
}
|
|
781
|
-
Object.entries(definition.properties).
|
|
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.
|
|
785
|
-
const sanitizedName = this.
|
|
786
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
841
|
-
return `${sanitizedKey}${questionMark}: ${this.
|
|
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
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
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
|
-
|
|
854
|
-
|
|
855
|
-
|
|
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
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
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.
|
|
995
|
+
const types = items.map((item) => this.resolveSwaggerTypeCached(item));
|
|
910
996
|
return `[${types.join(", ")}]`;
|
|
911
997
|
} else {
|
|
912
|
-
return this.
|
|
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("/").
|
|
2212
|
-
|
|
2213
|
-
|
|
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
|
|
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
|
-
|
|
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).
|
|
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
|
|
2467
|
-
typeGenerator
|
|
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 =
|
|
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
|
|
2491
|
-
const pluginGenerator =
|
|
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
|
}
|