ng-openapi 0.0.24 → 0.0.25-alpha.1
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 +417 -226
- package/index.d.ts +9 -1
- package/index.js +422 -222
- package/package.json +1 -1
package/cli.cjs
CHANGED
|
@@ -26,7 +26,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
26
26
|
|
|
27
27
|
// src/lib/cli.ts
|
|
28
28
|
var import_commander = require("commander");
|
|
29
|
-
var
|
|
29
|
+
var path9 = __toESM(require("path"));
|
|
30
30
|
var fs4 = __toESM(require("fs"));
|
|
31
31
|
|
|
32
32
|
// src/lib/core/swagger-parser.ts
|
|
@@ -58,7 +58,7 @@ var SwaggerParser = class {
|
|
|
58
58
|
};
|
|
59
59
|
|
|
60
60
|
// src/lib/core/generator.ts
|
|
61
|
-
var
|
|
61
|
+
var import_ts_morph5 = require("ts-morph");
|
|
62
62
|
|
|
63
63
|
// src/lib/generators/type/type.generator.ts
|
|
64
64
|
var import_ts_morph = require("ts-morph");
|
|
@@ -93,6 +93,10 @@ var PROVIDER_GENERATOR_HEADER_COMMENT = defaultHeaderComment + `* Generated prov
|
|
|
93
93
|
* Do not edit this file manually
|
|
94
94
|
*/
|
|
95
95
|
`;
|
|
96
|
+
var BASE_INTERCEPTOR_HEADER_COMMENT = /* @__PURE__ */ __name((clientName) => defaultHeaderComment + `* Generated Base Interceptor for client ${clientName}
|
|
97
|
+
* Do not edit this file manually
|
|
98
|
+
*/
|
|
99
|
+
`, "BASE_INTERCEPTOR_HEADER_COMMENT");
|
|
96
100
|
|
|
97
101
|
// src/lib/generators/type/type.generator.ts
|
|
98
102
|
var TypeGenerator = class {
|
|
@@ -402,8 +406,10 @@ var TokenGenerator = class {
|
|
|
402
406
|
__name(this, "TokenGenerator");
|
|
403
407
|
}
|
|
404
408
|
project;
|
|
405
|
-
|
|
409
|
+
clientName;
|
|
410
|
+
constructor(project, clientName = "default") {
|
|
406
411
|
this.project = project;
|
|
412
|
+
this.clientName = clientName;
|
|
407
413
|
}
|
|
408
414
|
generate(outputDir) {
|
|
409
415
|
const tokensDir = path.join(outputDir, "tokens");
|
|
@@ -413,29 +419,73 @@ var TokenGenerator = class {
|
|
|
413
419
|
});
|
|
414
420
|
sourceFile.addImportDeclaration({
|
|
415
421
|
namedImports: [
|
|
416
|
-
"InjectionToken"
|
|
422
|
+
"InjectionToken",
|
|
423
|
+
"HttpInterceptor"
|
|
417
424
|
],
|
|
418
425
|
moduleSpecifier: "@angular/core"
|
|
419
426
|
});
|
|
427
|
+
const basePathTokenName = this.getBasePathTokenName();
|
|
428
|
+
const interceptorsTokenName = this.getInterceptorsTokenName();
|
|
420
429
|
sourceFile.addVariableStatement({
|
|
421
430
|
isExported: true,
|
|
422
431
|
declarationKind: import_ts_morph2.VariableDeclarationKind.Const,
|
|
423
432
|
declarations: [
|
|
424
433
|
{
|
|
425
|
-
name:
|
|
426
|
-
initializer: `new InjectionToken<string>('
|
|
434
|
+
name: basePathTokenName,
|
|
435
|
+
initializer: `new InjectionToken<string>('${basePathTokenName}', {
|
|
427
436
|
providedIn: 'root',
|
|
428
437
|
factory: () => '/api', // Default fallback
|
|
429
438
|
})`
|
|
430
439
|
}
|
|
431
440
|
],
|
|
432
441
|
leadingTrivia: `/**
|
|
433
|
-
* Injection token for the base API path
|
|
442
|
+
* Injection token for the ${this.clientName} client base API path
|
|
443
|
+
*/
|
|
444
|
+
`
|
|
445
|
+
});
|
|
446
|
+
sourceFile.addVariableStatement({
|
|
447
|
+
isExported: true,
|
|
448
|
+
declarationKind: import_ts_morph2.VariableDeclarationKind.Const,
|
|
449
|
+
declarations: [
|
|
450
|
+
{
|
|
451
|
+
name: interceptorsTokenName,
|
|
452
|
+
initializer: `new InjectionToken<HttpInterceptor[]>('${interceptorsTokenName}', {
|
|
453
|
+
providedIn: 'root',
|
|
454
|
+
factory: () => [], // Default empty array
|
|
455
|
+
})`
|
|
456
|
+
}
|
|
457
|
+
],
|
|
458
|
+
leadingTrivia: `/**
|
|
459
|
+
* Injection token for the ${this.clientName} client HTTP interceptors
|
|
434
460
|
*/
|
|
435
461
|
`
|
|
436
462
|
});
|
|
463
|
+
if (this.clientName === "default") {
|
|
464
|
+
sourceFile.addVariableStatement({
|
|
465
|
+
isExported: true,
|
|
466
|
+
declarationKind: import_ts_morph2.VariableDeclarationKind.Const,
|
|
467
|
+
declarations: [
|
|
468
|
+
{
|
|
469
|
+
name: "BASE_PATH",
|
|
470
|
+
initializer: basePathTokenName
|
|
471
|
+
}
|
|
472
|
+
],
|
|
473
|
+
leadingTrivia: `/**
|
|
474
|
+
* @deprecated Use ${basePathTokenName} instead
|
|
475
|
+
*/
|
|
476
|
+
`
|
|
477
|
+
});
|
|
478
|
+
}
|
|
437
479
|
sourceFile.saveSync();
|
|
438
480
|
}
|
|
481
|
+
getBasePathTokenName() {
|
|
482
|
+
const clientSuffix = this.clientName.toUpperCase().replace(/[^A-Z0-9]/g, "_");
|
|
483
|
+
return `BASE_PATH_${clientSuffix}`;
|
|
484
|
+
}
|
|
485
|
+
getInterceptorsTokenName() {
|
|
486
|
+
const clientSuffix = this.clientName.toUpperCase().replace(/[^A-Z0-9]/g, "_");
|
|
487
|
+
return `HTTP_INTERCEPTORS_${clientSuffix}`;
|
|
488
|
+
}
|
|
439
489
|
};
|
|
440
490
|
|
|
441
491
|
// src/lib/generators/utility/file-download.generator.ts
|
|
@@ -757,9 +807,332 @@ var MainIndexGenerator = class {
|
|
|
757
807
|
}
|
|
758
808
|
};
|
|
759
809
|
|
|
760
|
-
// src/lib/generators/
|
|
761
|
-
var import_ts_morph3 = require("ts-morph");
|
|
810
|
+
// src/lib/generators/utility/provider.generator.ts
|
|
762
811
|
var path5 = __toESM(require("path"));
|
|
812
|
+
var ProviderGenerator = class {
|
|
813
|
+
static {
|
|
814
|
+
__name(this, "ProviderGenerator");
|
|
815
|
+
}
|
|
816
|
+
project;
|
|
817
|
+
config;
|
|
818
|
+
clientName;
|
|
819
|
+
constructor(project, config) {
|
|
820
|
+
this.project = project;
|
|
821
|
+
this.config = config;
|
|
822
|
+
this.clientName = config.clientName || "default";
|
|
823
|
+
}
|
|
824
|
+
generate(outputDir) {
|
|
825
|
+
const filePath = path5.join(outputDir, "providers.ts");
|
|
826
|
+
const sourceFile = this.project.createSourceFile(filePath, "", {
|
|
827
|
+
overwrite: true
|
|
828
|
+
});
|
|
829
|
+
sourceFile.insertText(0, PROVIDER_GENERATOR_HEADER_COMMENT);
|
|
830
|
+
const basePathTokenName = this.getBasePathTokenName();
|
|
831
|
+
const interceptorsTokenName = this.getInterceptorsTokenName();
|
|
832
|
+
const baseInterceptorClassName = `${this.capitalizeFirst(this.clientName)}BaseInterceptor`;
|
|
833
|
+
sourceFile.addImportDeclarations([
|
|
834
|
+
{
|
|
835
|
+
namedImports: [
|
|
836
|
+
"EnvironmentProviders",
|
|
837
|
+
"Provider",
|
|
838
|
+
"makeEnvironmentProviders"
|
|
839
|
+
],
|
|
840
|
+
moduleSpecifier: "@angular/core"
|
|
841
|
+
},
|
|
842
|
+
{
|
|
843
|
+
namedImports: [
|
|
844
|
+
"HTTP_INTERCEPTORS",
|
|
845
|
+
"HttpInterceptor"
|
|
846
|
+
],
|
|
847
|
+
moduleSpecifier: "@angular/common/http"
|
|
848
|
+
},
|
|
849
|
+
{
|
|
850
|
+
namedImports: [
|
|
851
|
+
basePathTokenName,
|
|
852
|
+
interceptorsTokenName
|
|
853
|
+
],
|
|
854
|
+
moduleSpecifier: "./tokens"
|
|
855
|
+
},
|
|
856
|
+
{
|
|
857
|
+
namedImports: [
|
|
858
|
+
baseInterceptorClassName
|
|
859
|
+
],
|
|
860
|
+
moduleSpecifier: "./utils/base-interceptor"
|
|
861
|
+
}
|
|
862
|
+
]);
|
|
863
|
+
if (this.config.options.dateType === "Date") {
|
|
864
|
+
sourceFile.addImportDeclaration({
|
|
865
|
+
namedImports: [
|
|
866
|
+
"DateInterceptor"
|
|
867
|
+
],
|
|
868
|
+
moduleSpecifier: "./utils/date-transformer"
|
|
869
|
+
});
|
|
870
|
+
}
|
|
871
|
+
sourceFile.addInterface({
|
|
872
|
+
name: `${this.capitalizeFirst(this.clientName)}Config`,
|
|
873
|
+
isExported: true,
|
|
874
|
+
docs: [
|
|
875
|
+
`Configuration options for ${this.clientName} client`
|
|
876
|
+
],
|
|
877
|
+
properties: [
|
|
878
|
+
{
|
|
879
|
+
name: "basePath",
|
|
880
|
+
type: "string",
|
|
881
|
+
docs: [
|
|
882
|
+
"Base API URL"
|
|
883
|
+
]
|
|
884
|
+
},
|
|
885
|
+
{
|
|
886
|
+
name: "enableDateTransform",
|
|
887
|
+
type: "boolean",
|
|
888
|
+
hasQuestionToken: true,
|
|
889
|
+
docs: [
|
|
890
|
+
"Enable automatic date transformation (default: true)"
|
|
891
|
+
]
|
|
892
|
+
},
|
|
893
|
+
{
|
|
894
|
+
name: "interceptors",
|
|
895
|
+
type: "HttpInterceptor[]",
|
|
896
|
+
hasQuestionToken: true,
|
|
897
|
+
docs: [
|
|
898
|
+
"Array of HTTP interceptors to apply to this client"
|
|
899
|
+
]
|
|
900
|
+
}
|
|
901
|
+
]
|
|
902
|
+
});
|
|
903
|
+
this.addMainProviderFunction(sourceFile, basePathTokenName, interceptorsTokenName, baseInterceptorClassName);
|
|
904
|
+
sourceFile.saveSync();
|
|
905
|
+
}
|
|
906
|
+
addMainProviderFunction(sourceFile, basePathTokenName, interceptorsTokenName, baseInterceptorClassName) {
|
|
907
|
+
const hasDateInterceptor = this.config.options.dateType === "Date";
|
|
908
|
+
const functionName = `provide${this.capitalizeFirst(this.clientName)}Client`;
|
|
909
|
+
const configTypeName = `${this.capitalizeFirst(this.clientName)}Config`;
|
|
910
|
+
const functionBody = `
|
|
911
|
+
const providers: Provider[] = [
|
|
912
|
+
// Base path token for this client
|
|
913
|
+
{
|
|
914
|
+
provide: ${basePathTokenName},
|
|
915
|
+
useValue: config.basePath
|
|
916
|
+
},
|
|
917
|
+
// Client-specific interceptors token
|
|
918
|
+
{
|
|
919
|
+
provide: ${interceptorsTokenName},
|
|
920
|
+
useValue: config.interceptors || []
|
|
921
|
+
},
|
|
922
|
+
// Base interceptor that handles client-specific interceptors
|
|
923
|
+
{
|
|
924
|
+
provide: HTTP_INTERCEPTORS,
|
|
925
|
+
useClass: ${baseInterceptorClassName},
|
|
926
|
+
multi: true
|
|
927
|
+
}
|
|
928
|
+
];
|
|
929
|
+
|
|
930
|
+
${hasDateInterceptor ? `// Add date interceptor to client-specific interceptors if enabled
|
|
931
|
+
if (config.enableDateTransform !== false) {
|
|
932
|
+
const currentInterceptors = config.interceptors || [];
|
|
933
|
+
providers.push({
|
|
934
|
+
provide: ${interceptorsTokenName},
|
|
935
|
+
useValue: [new DateInterceptor(), ...currentInterceptors]
|
|
936
|
+
});
|
|
937
|
+
}` : `// Date transformation not available (dateType: 'string' was used in generation)`}
|
|
938
|
+
|
|
939
|
+
return makeEnvironmentProviders(providers);`;
|
|
940
|
+
sourceFile.addFunction({
|
|
941
|
+
name: functionName,
|
|
942
|
+
isExported: true,
|
|
943
|
+
docs: [
|
|
944
|
+
`Provides configuration for ${this.clientName} client`,
|
|
945
|
+
"",
|
|
946
|
+
"@example",
|
|
947
|
+
"```typescript",
|
|
948
|
+
"// In your app.config.ts",
|
|
949
|
+
`import { ${functionName} } from './api/providers';`,
|
|
950
|
+
"",
|
|
951
|
+
"export const appConfig: ApplicationConfig = {",
|
|
952
|
+
" providers: [",
|
|
953
|
+
` ${functionName}({`,
|
|
954
|
+
" basePath: 'https://api.example.com',",
|
|
955
|
+
" interceptors: [new LoggingInterceptor(), new AuthInterceptor()]",
|
|
956
|
+
" }),",
|
|
957
|
+
" // other providers...",
|
|
958
|
+
" ]",
|
|
959
|
+
"};",
|
|
960
|
+
"```"
|
|
961
|
+
],
|
|
962
|
+
parameters: [
|
|
963
|
+
{
|
|
964
|
+
name: "config",
|
|
965
|
+
type: configTypeName
|
|
966
|
+
}
|
|
967
|
+
],
|
|
968
|
+
returnType: "EnvironmentProviders",
|
|
969
|
+
statements: functionBody
|
|
970
|
+
});
|
|
971
|
+
if (this.clientName === "default") {
|
|
972
|
+
sourceFile.addFunction({
|
|
973
|
+
name: "provideNgOpenapi",
|
|
974
|
+
isExported: true,
|
|
975
|
+
docs: [
|
|
976
|
+
"@deprecated Use provideDefaultClient instead for better clarity",
|
|
977
|
+
"Provides configuration for the default client"
|
|
978
|
+
],
|
|
979
|
+
parameters: [
|
|
980
|
+
{
|
|
981
|
+
name: "config",
|
|
982
|
+
type: configTypeName
|
|
983
|
+
}
|
|
984
|
+
],
|
|
985
|
+
returnType: "EnvironmentProviders",
|
|
986
|
+
statements: `return ${functionName}(config);`
|
|
987
|
+
});
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
getBasePathTokenName() {
|
|
991
|
+
const clientSuffix = this.clientName.toUpperCase().replace(/[^A-Z0-9]/g, "_");
|
|
992
|
+
return `BASE_PATH_${clientSuffix}`;
|
|
993
|
+
}
|
|
994
|
+
getInterceptorsTokenName() {
|
|
995
|
+
const clientSuffix = this.clientName.toUpperCase().replace(/[^A-Z0-9]/g, "_");
|
|
996
|
+
return `HTTP_INTERCEPTORS_${clientSuffix}`;
|
|
997
|
+
}
|
|
998
|
+
capitalizeFirst(str) {
|
|
999
|
+
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
1000
|
+
}
|
|
1001
|
+
};
|
|
1002
|
+
|
|
1003
|
+
// src/lib/generators/utility/base-interceptor.generator.ts
|
|
1004
|
+
var import_ts_morph3 = require("ts-morph");
|
|
1005
|
+
var path6 = __toESM(require("path"));
|
|
1006
|
+
var BaseInterceptorGenerator = class {
|
|
1007
|
+
static {
|
|
1008
|
+
__name(this, "BaseInterceptorGenerator");
|
|
1009
|
+
}
|
|
1010
|
+
#project;
|
|
1011
|
+
#clientName;
|
|
1012
|
+
constructor(project, clientName = "default") {
|
|
1013
|
+
this.#project = project;
|
|
1014
|
+
this.#clientName = clientName;
|
|
1015
|
+
}
|
|
1016
|
+
generate(outputDir) {
|
|
1017
|
+
const utilsDir = path6.join(outputDir, "utils");
|
|
1018
|
+
const filePath = path6.join(utilsDir, "base-interceptor.ts");
|
|
1019
|
+
const sourceFile = this.#project.createSourceFile(filePath, "", {
|
|
1020
|
+
overwrite: true
|
|
1021
|
+
});
|
|
1022
|
+
sourceFile.insertText(0, BASE_INTERCEPTOR_HEADER_COMMENT(this.#clientName));
|
|
1023
|
+
const basePathTokenName = this.getBasePathTokenName();
|
|
1024
|
+
const interceptorsTokenName = this.getInterceptorsTokenName();
|
|
1025
|
+
sourceFile.addImportDeclarations([
|
|
1026
|
+
{
|
|
1027
|
+
namedImports: [
|
|
1028
|
+
"HttpEvent",
|
|
1029
|
+
"HttpHandler",
|
|
1030
|
+
"HttpInterceptor",
|
|
1031
|
+
"HttpRequest"
|
|
1032
|
+
],
|
|
1033
|
+
moduleSpecifier: "@angular/common/http"
|
|
1034
|
+
},
|
|
1035
|
+
{
|
|
1036
|
+
namedImports: [
|
|
1037
|
+
"inject",
|
|
1038
|
+
"Injectable"
|
|
1039
|
+
],
|
|
1040
|
+
moduleSpecifier: "@angular/core"
|
|
1041
|
+
},
|
|
1042
|
+
{
|
|
1043
|
+
namedImports: [
|
|
1044
|
+
"Observable"
|
|
1045
|
+
],
|
|
1046
|
+
moduleSpecifier: "rxjs"
|
|
1047
|
+
},
|
|
1048
|
+
{
|
|
1049
|
+
namedImports: [
|
|
1050
|
+
basePathTokenName,
|
|
1051
|
+
interceptorsTokenName
|
|
1052
|
+
],
|
|
1053
|
+
moduleSpecifier: "../tokens"
|
|
1054
|
+
}
|
|
1055
|
+
]);
|
|
1056
|
+
sourceFile.addClass({
|
|
1057
|
+
name: `${this.capitalizeFirst(this.#clientName)}BaseInterceptor`,
|
|
1058
|
+
isExported: true,
|
|
1059
|
+
decorators: [
|
|
1060
|
+
{
|
|
1061
|
+
name: "Injectable",
|
|
1062
|
+
arguments: []
|
|
1063
|
+
}
|
|
1064
|
+
],
|
|
1065
|
+
implements: [
|
|
1066
|
+
"HttpInterceptor"
|
|
1067
|
+
],
|
|
1068
|
+
properties: [
|
|
1069
|
+
{
|
|
1070
|
+
name: "basePath",
|
|
1071
|
+
type: "string",
|
|
1072
|
+
scope: import_ts_morph3.Scope.Private,
|
|
1073
|
+
isReadonly: true,
|
|
1074
|
+
initializer: `inject(${basePathTokenName})`
|
|
1075
|
+
},
|
|
1076
|
+
{
|
|
1077
|
+
name: "httpInterceptors",
|
|
1078
|
+
type: "HttpInterceptor[]",
|
|
1079
|
+
scope: import_ts_morph3.Scope.Private,
|
|
1080
|
+
isReadonly: true,
|
|
1081
|
+
initializer: `inject(${interceptorsTokenName})`
|
|
1082
|
+
}
|
|
1083
|
+
],
|
|
1084
|
+
methods: [
|
|
1085
|
+
{
|
|
1086
|
+
name: "intercept",
|
|
1087
|
+
parameters: [
|
|
1088
|
+
{
|
|
1089
|
+
name: "req",
|
|
1090
|
+
type: "HttpRequest<any>"
|
|
1091
|
+
},
|
|
1092
|
+
{
|
|
1093
|
+
name: "next",
|
|
1094
|
+
type: "HttpHandler"
|
|
1095
|
+
}
|
|
1096
|
+
],
|
|
1097
|
+
returnType: "Observable<HttpEvent<any>>",
|
|
1098
|
+
statements: `
|
|
1099
|
+
// Only intercept requests to this client's base path
|
|
1100
|
+
if (!req.url.startsWith(this.#basePath)) {
|
|
1101
|
+
return next.handle(req);
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
// Apply client-specific interceptors in reverse order
|
|
1105
|
+
let handler = next;
|
|
1106
|
+
|
|
1107
|
+
handler = this.#httpInterceptors.reduceRight(
|
|
1108
|
+
(next, interceptor) => ({
|
|
1109
|
+
handle: (request: HttpRequest<any>) => interceptor.intercept(request, next)
|
|
1110
|
+
}),
|
|
1111
|
+
handler
|
|
1112
|
+
);
|
|
1113
|
+
|
|
1114
|
+
return handler.handle(req);`
|
|
1115
|
+
}
|
|
1116
|
+
]
|
|
1117
|
+
});
|
|
1118
|
+
sourceFile.saveSync();
|
|
1119
|
+
}
|
|
1120
|
+
getBasePathTokenName() {
|
|
1121
|
+
const clientSuffix = this.#clientName.toUpperCase().replace(/[^A-Z0-9]/g, "_");
|
|
1122
|
+
return `BASE_PATH_${clientSuffix}`;
|
|
1123
|
+
}
|
|
1124
|
+
getInterceptorsTokenName() {
|
|
1125
|
+
const clientSuffix = this.#clientName.toUpperCase().replace(/[^A-Z0-9]/g, "_");
|
|
1126
|
+
return `HTTP_INTERCEPTORS_${clientSuffix}`;
|
|
1127
|
+
}
|
|
1128
|
+
capitalizeFirst(str) {
|
|
1129
|
+
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
1130
|
+
}
|
|
1131
|
+
};
|
|
1132
|
+
|
|
1133
|
+
// src/lib/generators/service/service.generator.ts
|
|
1134
|
+
var import_ts_morph4 = require("ts-morph");
|
|
1135
|
+
var path7 = __toESM(require("path"));
|
|
763
1136
|
|
|
764
1137
|
// src/lib/utils/string.utils.ts
|
|
765
1138
|
function camelCase(str) {
|
|
@@ -1551,7 +1924,7 @@ var ServiceGenerator = class {
|
|
|
1551
1924
|
this.methodGenerator = new ServiceMethodGenerator(config);
|
|
1552
1925
|
}
|
|
1553
1926
|
generate(outputRoot) {
|
|
1554
|
-
const outputDir =
|
|
1927
|
+
const outputDir = path7.join(outputRoot, "services");
|
|
1555
1928
|
const paths = this.extractPaths();
|
|
1556
1929
|
const controllerGroups = this.groupPathsByController(paths);
|
|
1557
1930
|
Object.entries(controllerGroups).forEach(([controllerName, operations]) => {
|
|
@@ -1561,7 +1934,7 @@ var ServiceGenerator = class {
|
|
|
1561
1934
|
extractPaths() {
|
|
1562
1935
|
const paths = [];
|
|
1563
1936
|
const swaggerPaths = this.spec.paths || {};
|
|
1564
|
-
Object.entries(swaggerPaths).forEach(([
|
|
1937
|
+
Object.entries(swaggerPaths).forEach(([path10, pathItem]) => {
|
|
1565
1938
|
const methods = [
|
|
1566
1939
|
"get",
|
|
1567
1940
|
"post",
|
|
@@ -1575,7 +1948,7 @@ var ServiceGenerator = class {
|
|
|
1575
1948
|
if (pathItem[method]) {
|
|
1576
1949
|
const operation = pathItem[method];
|
|
1577
1950
|
paths.push({
|
|
1578
|
-
path:
|
|
1951
|
+
path: path10,
|
|
1579
1952
|
method: method.toUpperCase(),
|
|
1580
1953
|
operationId: operation.operationId,
|
|
1581
1954
|
summary: operation.summary,
|
|
@@ -1607,12 +1980,12 @@ var ServiceGenerator = class {
|
|
|
1607
1980
|
}
|
|
1608
1981
|
groupPathsByController(paths) {
|
|
1609
1982
|
const groups = {};
|
|
1610
|
-
paths.forEach((
|
|
1983
|
+
paths.forEach((path10) => {
|
|
1611
1984
|
let controllerName = "Default";
|
|
1612
|
-
if (
|
|
1613
|
-
controllerName =
|
|
1985
|
+
if (path10.tags && path10.tags.length > 0) {
|
|
1986
|
+
controllerName = path10.tags[0];
|
|
1614
1987
|
} else {
|
|
1615
|
-
const pathParts =
|
|
1988
|
+
const pathParts = path10.path.split("/").filter((p) => p && !p.startsWith("{"));
|
|
1616
1989
|
if (pathParts.length > 1) {
|
|
1617
1990
|
controllerName = pascalCase(pathParts[1]);
|
|
1618
1991
|
}
|
|
@@ -1621,13 +1994,13 @@ var ServiceGenerator = class {
|
|
|
1621
1994
|
if (!groups[controllerName]) {
|
|
1622
1995
|
groups[controllerName] = [];
|
|
1623
1996
|
}
|
|
1624
|
-
groups[controllerName].push(
|
|
1997
|
+
groups[controllerName].push(path10);
|
|
1625
1998
|
});
|
|
1626
1999
|
return groups;
|
|
1627
2000
|
}
|
|
1628
2001
|
generateServiceFile(controllerName, operations, outputDir) {
|
|
1629
2002
|
const fileName = `${camelCase(controllerName)}.service.ts`;
|
|
1630
|
-
const filePath =
|
|
2003
|
+
const filePath = path7.join(outputDir, fileName);
|
|
1631
2004
|
const sourceFile = this.project.createSourceFile(filePath, "", {
|
|
1632
2005
|
overwrite: true
|
|
1633
2006
|
});
|
|
@@ -1702,6 +2075,7 @@ var ServiceGenerator = class {
|
|
|
1702
2075
|
});
|
|
1703
2076
|
}
|
|
1704
2077
|
addImports(sourceFile, usedTypes) {
|
|
2078
|
+
const basePathTokenName = this.getBasePathTokenName();
|
|
1705
2079
|
sourceFile.addImportDeclarations([
|
|
1706
2080
|
{
|
|
1707
2081
|
namedImports: [
|
|
@@ -1729,7 +2103,7 @@ var ServiceGenerator = class {
|
|
|
1729
2103
|
},
|
|
1730
2104
|
{
|
|
1731
2105
|
namedImports: [
|
|
1732
|
-
|
|
2106
|
+
basePathTokenName
|
|
1733
2107
|
],
|
|
1734
2108
|
moduleSpecifier: "../tokens"
|
|
1735
2109
|
}
|
|
@@ -1743,6 +2117,7 @@ var ServiceGenerator = class {
|
|
|
1743
2117
|
}
|
|
1744
2118
|
addServiceClass(sourceFile, controllerName, operations) {
|
|
1745
2119
|
const className = `${controllerName}Service`;
|
|
2120
|
+
const basePathTokenName = this.getBasePathTokenName();
|
|
1746
2121
|
sourceFile.insertText(0, SERVICE_GENERATOR_HEADER_COMMENT(controllerName));
|
|
1747
2122
|
const serviceClass = sourceFile.addClass({
|
|
1748
2123
|
name: className,
|
|
@@ -1759,16 +2134,16 @@ var ServiceGenerator = class {
|
|
|
1759
2134
|
serviceClass.addProperty({
|
|
1760
2135
|
name: "httpClient",
|
|
1761
2136
|
type: "HttpClient",
|
|
1762
|
-
scope:
|
|
2137
|
+
scope: import_ts_morph4.Scope.Private,
|
|
1763
2138
|
isReadonly: true,
|
|
1764
2139
|
initializer: "inject(HttpClient)"
|
|
1765
2140
|
});
|
|
1766
2141
|
serviceClass.addProperty({
|
|
1767
2142
|
name: "basePath",
|
|
1768
2143
|
type: "string",
|
|
1769
|
-
scope:
|
|
2144
|
+
scope: import_ts_morph4.Scope.Private,
|
|
1770
2145
|
isReadonly: true,
|
|
1771
|
-
initializer:
|
|
2146
|
+
initializer: `inject(${basePathTokenName})`
|
|
1772
2147
|
});
|
|
1773
2148
|
operations.forEach((operation) => {
|
|
1774
2149
|
this.methodGenerator.addServiceMethod(serviceClass, operation);
|
|
@@ -1777,6 +2152,11 @@ var ServiceGenerator = class {
|
|
|
1777
2152
|
throw new Error(`Duplicate method names found in service class ${className}. Please ensure unique method names for each operation.`);
|
|
1778
2153
|
}
|
|
1779
2154
|
}
|
|
2155
|
+
getBasePathTokenName() {
|
|
2156
|
+
const clientName = this.config.clientName || "default";
|
|
2157
|
+
const clientSuffix = clientName.toUpperCase().replace(/[^A-Z0-9]/g, "_");
|
|
2158
|
+
return `BASE_PATH_${clientSuffix}`;
|
|
2159
|
+
}
|
|
1780
2160
|
hasDuplicateMethodNames(arr) {
|
|
1781
2161
|
return new Set(arr.map((method) => method.getName())).size !== arr.length;
|
|
1782
2162
|
}
|
|
@@ -1784,7 +2164,7 @@ var ServiceGenerator = class {
|
|
|
1784
2164
|
|
|
1785
2165
|
// src/lib/generators/service/service-index.generator.ts
|
|
1786
2166
|
var fs2 = __toESM(require("fs"));
|
|
1787
|
-
var
|
|
2167
|
+
var path8 = __toESM(require("path"));
|
|
1788
2168
|
var ServiceIndexGenerator = class {
|
|
1789
2169
|
static {
|
|
1790
2170
|
__name(this, "ServiceIndexGenerator");
|
|
@@ -1794,8 +2174,8 @@ var ServiceIndexGenerator = class {
|
|
|
1794
2174
|
this.project = project;
|
|
1795
2175
|
}
|
|
1796
2176
|
generateIndex(outputRoot) {
|
|
1797
|
-
const servicesDir =
|
|
1798
|
-
const indexPath =
|
|
2177
|
+
const servicesDir = path8.join(outputRoot, "services");
|
|
2178
|
+
const indexPath = path8.join(servicesDir, "index.ts");
|
|
1799
2179
|
const sourceFile = this.project.createSourceFile(indexPath, "", {
|
|
1800
2180
|
overwrite: true
|
|
1801
2181
|
});
|
|
@@ -1814,198 +2194,6 @@ var ServiceIndexGenerator = class {
|
|
|
1814
2194
|
}
|
|
1815
2195
|
};
|
|
1816
2196
|
|
|
1817
|
-
// src/lib/generators/utility/provider.generator.ts
|
|
1818
|
-
var path7 = __toESM(require("path"));
|
|
1819
|
-
var ProviderGenerator = class {
|
|
1820
|
-
static {
|
|
1821
|
-
__name(this, "ProviderGenerator");
|
|
1822
|
-
}
|
|
1823
|
-
project;
|
|
1824
|
-
config;
|
|
1825
|
-
constructor(project, config) {
|
|
1826
|
-
this.project = project;
|
|
1827
|
-
this.config = config;
|
|
1828
|
-
}
|
|
1829
|
-
generate(outputDir) {
|
|
1830
|
-
const filePath = path7.join(outputDir, "providers.ts");
|
|
1831
|
-
const sourceFile = this.project.createSourceFile(filePath, "", {
|
|
1832
|
-
overwrite: true
|
|
1833
|
-
});
|
|
1834
|
-
sourceFile.insertText(0, PROVIDER_GENERATOR_HEADER_COMMENT);
|
|
1835
|
-
sourceFile.addImportDeclarations([
|
|
1836
|
-
{
|
|
1837
|
-
namedImports: [
|
|
1838
|
-
"EnvironmentProviders",
|
|
1839
|
-
"Provider",
|
|
1840
|
-
"makeEnvironmentProviders"
|
|
1841
|
-
],
|
|
1842
|
-
moduleSpecifier: "@angular/core"
|
|
1843
|
-
},
|
|
1844
|
-
{
|
|
1845
|
-
namedImports: [
|
|
1846
|
-
"HTTP_INTERCEPTORS"
|
|
1847
|
-
],
|
|
1848
|
-
moduleSpecifier: "@angular/common/http"
|
|
1849
|
-
},
|
|
1850
|
-
{
|
|
1851
|
-
namedImports: [
|
|
1852
|
-
"BASE_PATH"
|
|
1853
|
-
],
|
|
1854
|
-
moduleSpecifier: "./tokens"
|
|
1855
|
-
}
|
|
1856
|
-
]);
|
|
1857
|
-
if (this.config.options.dateType === "Date") {
|
|
1858
|
-
sourceFile.addImportDeclaration({
|
|
1859
|
-
namedImports: [
|
|
1860
|
-
"DateInterceptor"
|
|
1861
|
-
],
|
|
1862
|
-
moduleSpecifier: "./utils/date-transformer"
|
|
1863
|
-
});
|
|
1864
|
-
}
|
|
1865
|
-
sourceFile.addInterface({
|
|
1866
|
-
name: "NgOpenapiConfig",
|
|
1867
|
-
isExported: true,
|
|
1868
|
-
docs: [
|
|
1869
|
-
"Configuration options for ng-openapi providers"
|
|
1870
|
-
],
|
|
1871
|
-
properties: [
|
|
1872
|
-
{
|
|
1873
|
-
name: "basePath",
|
|
1874
|
-
type: "string",
|
|
1875
|
-
docs: [
|
|
1876
|
-
"Base API URL"
|
|
1877
|
-
]
|
|
1878
|
-
},
|
|
1879
|
-
{
|
|
1880
|
-
name: "enableDateTransform",
|
|
1881
|
-
type: "boolean",
|
|
1882
|
-
hasQuestionToken: true,
|
|
1883
|
-
docs: [
|
|
1884
|
-
"Enable automatic date transformation (default: true)"
|
|
1885
|
-
]
|
|
1886
|
-
}
|
|
1887
|
-
]
|
|
1888
|
-
});
|
|
1889
|
-
this.addMainProviderFunction(sourceFile);
|
|
1890
|
-
this.addAsyncProviderFunction(sourceFile);
|
|
1891
|
-
sourceFile.saveSync();
|
|
1892
|
-
}
|
|
1893
|
-
addMainProviderFunction(sourceFile) {
|
|
1894
|
-
const hasDateInterceptor = this.config.options.dateType === "Date";
|
|
1895
|
-
const functionBody = `
|
|
1896
|
-
const providers: Provider[] = [
|
|
1897
|
-
// Base path token
|
|
1898
|
-
{
|
|
1899
|
-
provide: BASE_PATH,
|
|
1900
|
-
useValue: config.basePath
|
|
1901
|
-
}
|
|
1902
|
-
];
|
|
1903
|
-
|
|
1904
|
-
${hasDateInterceptor ? `// Add date interceptor if enabled (default: true)
|
|
1905
|
-
if (config.enableDateTransform !== false) {
|
|
1906
|
-
providers.push({
|
|
1907
|
-
provide: HTTP_INTERCEPTORS,
|
|
1908
|
-
useClass: DateInterceptor,
|
|
1909
|
-
multi: true
|
|
1910
|
-
});
|
|
1911
|
-
}` : `// Date transformation not available (dateType: 'string' was used in generation)`}
|
|
1912
|
-
|
|
1913
|
-
return makeEnvironmentProviders(providers);`;
|
|
1914
|
-
sourceFile.addFunction({
|
|
1915
|
-
name: "provideNgOpenapi",
|
|
1916
|
-
isExported: true,
|
|
1917
|
-
docs: [
|
|
1918
|
-
"Provides all necessary configuration for ng-openapi generated services",
|
|
1919
|
-
"",
|
|
1920
|
-
"@example",
|
|
1921
|
-
"```typescript",
|
|
1922
|
-
"// In your app.config.ts",
|
|
1923
|
-
"import { provideNgOpenapi } from './api/providers';",
|
|
1924
|
-
"",
|
|
1925
|
-
"export const appConfig: ApplicationConfig = {",
|
|
1926
|
-
" providers: [",
|
|
1927
|
-
" provideNgOpenapi({",
|
|
1928
|
-
" basePath: 'https://api.example.com'",
|
|
1929
|
-
" }),",
|
|
1930
|
-
" // other providers...",
|
|
1931
|
-
" ]",
|
|
1932
|
-
"};",
|
|
1933
|
-
"```"
|
|
1934
|
-
],
|
|
1935
|
-
parameters: [
|
|
1936
|
-
{
|
|
1937
|
-
name: "config",
|
|
1938
|
-
type: "NgOpenapiConfig"
|
|
1939
|
-
}
|
|
1940
|
-
],
|
|
1941
|
-
returnType: "EnvironmentProviders",
|
|
1942
|
-
statements: functionBody
|
|
1943
|
-
});
|
|
1944
|
-
}
|
|
1945
|
-
addAsyncProviderFunction(sourceFile) {
|
|
1946
|
-
const hasDateInterceptor = this.config.options.dateType === "Date";
|
|
1947
|
-
const functionBody = `
|
|
1948
|
-
const providers: Provider[] = [];
|
|
1949
|
-
|
|
1950
|
-
// Handle async base path
|
|
1951
|
-
if (typeof config.basePath === 'string') {
|
|
1952
|
-
providers.push({
|
|
1953
|
-
provide: BASE_PATH,
|
|
1954
|
-
useValue: config.basePath
|
|
1955
|
-
});
|
|
1956
|
-
} else {
|
|
1957
|
-
providers.push({
|
|
1958
|
-
provide: BASE_PATH,
|
|
1959
|
-
useFactory: config.basePath
|
|
1960
|
-
});
|
|
1961
|
-
}
|
|
1962
|
-
|
|
1963
|
-
${hasDateInterceptor ? `// Add date interceptor if enabled (default: true)
|
|
1964
|
-
if (config.enableDateTransform !== false) {
|
|
1965
|
-
providers.push({
|
|
1966
|
-
provide: HTTP_INTERCEPTORS,
|
|
1967
|
-
useClass: DateInterceptor,
|
|
1968
|
-
multi: true
|
|
1969
|
-
});
|
|
1970
|
-
}` : `// Date transformation not available (dateType: 'string' was used in generation)`}
|
|
1971
|
-
|
|
1972
|
-
return makeEnvironmentProviders(providers);`;
|
|
1973
|
-
sourceFile.addFunction({
|
|
1974
|
-
name: "provideNgOpenapiAsync",
|
|
1975
|
-
isExported: true,
|
|
1976
|
-
docs: [
|
|
1977
|
-
"Alternative function for cases where you need to handle async configuration",
|
|
1978
|
-
"",
|
|
1979
|
-
"@example",
|
|
1980
|
-
"```typescript",
|
|
1981
|
-
"// In your app.config.ts",
|
|
1982
|
-
"import { provideNgOpenapiAsync } from './api/providers';",
|
|
1983
|
-
"",
|
|
1984
|
-
"export const appConfig: ApplicationConfig = {",
|
|
1985
|
-
" providers: [",
|
|
1986
|
-
" provideNgOpenapiAsync({",
|
|
1987
|
-
" basePath: () => import('./config').then(c => c.apiConfig.baseUrl)",
|
|
1988
|
-
" }),",
|
|
1989
|
-
" // other providers...",
|
|
1990
|
-
" ]",
|
|
1991
|
-
"};",
|
|
1992
|
-
"```"
|
|
1993
|
-
],
|
|
1994
|
-
parameters: [
|
|
1995
|
-
{
|
|
1996
|
-
name: "config",
|
|
1997
|
-
type: `{
|
|
1998
|
-
basePath: string | (() => Promise<string>);
|
|
1999
|
-
enableDateTransform?: boolean;
|
|
2000
|
-
}`
|
|
2001
|
-
}
|
|
2002
|
-
],
|
|
2003
|
-
returnType: "EnvironmentProviders",
|
|
2004
|
-
statements: functionBody
|
|
2005
|
-
});
|
|
2006
|
-
}
|
|
2007
|
-
};
|
|
2008
|
-
|
|
2009
2197
|
// src/lib/core/generator.ts
|
|
2010
2198
|
var fs3 = __toESM(require("fs"));
|
|
2011
2199
|
async function generateFromConfig(config) {
|
|
@@ -2020,11 +2208,11 @@ async function generateFromConfig(config) {
|
|
|
2020
2208
|
});
|
|
2021
2209
|
}
|
|
2022
2210
|
try {
|
|
2023
|
-
const project = new
|
|
2211
|
+
const project = new import_ts_morph5.Project({
|
|
2024
2212
|
compilerOptions: {
|
|
2025
2213
|
declaration: true,
|
|
2026
|
-
target:
|
|
2027
|
-
module:
|
|
2214
|
+
target: import_ts_morph5.ScriptTarget.ES2022,
|
|
2215
|
+
module: import_ts_morph5.ModuleKind.Preserve,
|
|
2028
2216
|
strict: true,
|
|
2029
2217
|
...config.compilerOptions
|
|
2030
2218
|
}
|
|
@@ -2038,11 +2226,9 @@ async function generateFromConfig(config) {
|
|
|
2038
2226
|
if (config.options.dateType === "Date") {
|
|
2039
2227
|
const dateTransformer = new DateTransformerGenerator(project);
|
|
2040
2228
|
dateTransformer.generate(outputPath);
|
|
2041
|
-
console.log(`\u2705 Date transformer generated`);
|
|
2042
2229
|
}
|
|
2043
2230
|
const fileDownloadHelper = new FileDownloadGenerator(project);
|
|
2044
2231
|
fileDownloadHelper.generate(outputPath);
|
|
2045
|
-
console.log(`\u2705 File download helper generated`);
|
|
2046
2232
|
const serviceGenerator = new ServiceGenerator(config.input, project, config);
|
|
2047
2233
|
serviceGenerator.generate(outputPath);
|
|
2048
2234
|
const indexGenerator = new ServiceIndexGenerator(project);
|
|
@@ -2050,11 +2236,16 @@ async function generateFromConfig(config) {
|
|
|
2050
2236
|
console.log(`\u2705 Angular services generated`);
|
|
2051
2237
|
const providerGenerator = new ProviderGenerator(project, config);
|
|
2052
2238
|
providerGenerator.generate(outputPath);
|
|
2053
|
-
|
|
2239
|
+
const baseInterceptorGenerator = new BaseInterceptorGenerator(project, config.clientName);
|
|
2240
|
+
baseInterceptorGenerator.generate(outputPath);
|
|
2054
2241
|
}
|
|
2055
2242
|
const mainIndexGenerator = new MainIndexGenerator(project, config);
|
|
2056
2243
|
mainIndexGenerator.generateMainIndex(outputPath);
|
|
2057
|
-
|
|
2244
|
+
if (config.clientName) {
|
|
2245
|
+
console.log(`\u{1F389} ${config.clientName} Generation completed successfully at: ${outputPath}`);
|
|
2246
|
+
} else {
|
|
2247
|
+
console.log("\u{1F389} Generation completed successfully at:", outputPath);
|
|
2248
|
+
}
|
|
2058
2249
|
} catch (error) {
|
|
2059
2250
|
if (error instanceof Error) {
|
|
2060
2251
|
console.error("\u274C Error during generation:", error.message);
|
|
@@ -2069,7 +2260,7 @@ __name(generateFromConfig, "generateFromConfig");
|
|
|
2069
2260
|
// src/lib/cli.ts
|
|
2070
2261
|
var program = new import_commander.Command();
|
|
2071
2262
|
async function loadConfigFile(configPath) {
|
|
2072
|
-
const resolvedPath =
|
|
2263
|
+
const resolvedPath = path9.resolve(configPath);
|
|
2073
2264
|
if (!fs4.existsSync(resolvedPath)) {
|
|
2074
2265
|
throw new Error(`Configuration file not found: ${resolvedPath}`);
|
|
2075
2266
|
}
|
|
@@ -2095,7 +2286,7 @@ async function generateFromOptions(options) {
|
|
|
2095
2286
|
const config = await loadConfigFile(options.config);
|
|
2096
2287
|
await generateFromConfig(config);
|
|
2097
2288
|
} else if (options.input) {
|
|
2098
|
-
const inputPath =
|
|
2289
|
+
const inputPath = path9.resolve(options.input);
|
|
2099
2290
|
if (!fs4.existsSync(inputPath)) {
|
|
2100
2291
|
console.error(`Error: Input file not found: ${inputPath}`);
|
|
2101
2292
|
process.exit(1);
|