ng-openapi 0.0.21 → 0.0.23
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 +270 -102
- package/index.d.ts +2 -0
- package/index.js +157 -92
- package/package.json +1 -1
package/cli.cjs
CHANGED
|
@@ -7,6 +7,10 @@ var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
|
7
7
|
var __getProtoOf = Object.getPrototypeOf;
|
|
8
8
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
9
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
10
|
+
var __export = (target, all) => {
|
|
11
|
+
for (var name in all)
|
|
12
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
13
|
+
};
|
|
10
14
|
var __copyProps = (to, from, except, desc) => {
|
|
11
15
|
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
16
|
for (let key of __getOwnPropNames(from))
|
|
@@ -23,8 +27,14 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
23
27
|
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
24
28
|
mod
|
|
25
29
|
));
|
|
30
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
26
31
|
|
|
27
32
|
// src/lib/cli.ts
|
|
33
|
+
var cli_exports = {};
|
|
34
|
+
__export(cli_exports, {
|
|
35
|
+
generateFromOptions: () => generateFromOptions
|
|
36
|
+
});
|
|
37
|
+
module.exports = __toCommonJS(cli_exports);
|
|
28
38
|
var import_commander = require("commander");
|
|
29
39
|
var path8 = __toESM(require("path"));
|
|
30
40
|
var fs4 = __toESM(require("fs"));
|
|
@@ -402,8 +412,10 @@ var TokenGenerator = class {
|
|
|
402
412
|
__name(this, "TokenGenerator");
|
|
403
413
|
}
|
|
404
414
|
project;
|
|
405
|
-
|
|
415
|
+
config;
|
|
416
|
+
constructor(project, config) {
|
|
406
417
|
this.project = project;
|
|
418
|
+
this.config = config;
|
|
407
419
|
}
|
|
408
420
|
generate(outputDir) {
|
|
409
421
|
const tokensDir = path.join(outputDir, "tokens");
|
|
@@ -417,23 +429,55 @@ var TokenGenerator = class {
|
|
|
417
429
|
],
|
|
418
430
|
moduleSpecifier: "@angular/core"
|
|
419
431
|
});
|
|
432
|
+
const clientName = this.config.clientName || "DEFAULT";
|
|
433
|
+
const upperCaseClientName = clientName.toUpperCase().replace(/[^A-Z0-9]/g, "_");
|
|
420
434
|
sourceFile.addVariableStatement({
|
|
421
435
|
isExported: true,
|
|
422
436
|
declarationKind: import_ts_morph2.VariableDeclarationKind.Const,
|
|
423
437
|
declarations: [
|
|
424
438
|
{
|
|
425
|
-
name:
|
|
426
|
-
initializer: `new InjectionToken<string>('
|
|
439
|
+
name: `${upperCaseClientName}_BASE_PATH`,
|
|
440
|
+
initializer: `new InjectionToken<string>('${upperCaseClientName}_BASE_PATH', {
|
|
427
441
|
providedIn: 'root',
|
|
428
|
-
factory: () => '/api',
|
|
442
|
+
factory: () => '/api',
|
|
429
443
|
})`
|
|
430
444
|
}
|
|
431
445
|
],
|
|
432
446
|
leadingTrivia: `/**
|
|
433
|
-
*
|
|
447
|
+
* Base path token for ${clientName} client
|
|
448
|
+
*/
|
|
449
|
+
`
|
|
450
|
+
});
|
|
451
|
+
sourceFile.addVariableStatement({
|
|
452
|
+
isExported: true,
|
|
453
|
+
declarationKind: import_ts_morph2.VariableDeclarationKind.Const,
|
|
454
|
+
declarations: [
|
|
455
|
+
{
|
|
456
|
+
name: `${upperCaseClientName}_HTTP_CLIENT`,
|
|
457
|
+
initializer: `new InjectionToken<HttpClient>('${upperCaseClientName}_HTTP_CLIENT')`
|
|
458
|
+
}
|
|
459
|
+
],
|
|
460
|
+
leadingTrivia: `/**
|
|
461
|
+
* HTTP client token for ${clientName} client
|
|
434
462
|
*/
|
|
435
463
|
`
|
|
436
464
|
});
|
|
465
|
+
if (!this.config.clientName) {
|
|
466
|
+
sourceFile.addVariableStatement({
|
|
467
|
+
isExported: true,
|
|
468
|
+
declarationKind: import_ts_morph2.VariableDeclarationKind.Const,
|
|
469
|
+
declarations: [
|
|
470
|
+
{
|
|
471
|
+
name: "BASE_PATH",
|
|
472
|
+
initializer: `${upperCaseClientName}_BASE_PATH`
|
|
473
|
+
}
|
|
474
|
+
],
|
|
475
|
+
leadingTrivia: `/**
|
|
476
|
+
* @deprecated Use ${upperCaseClientName}_BASE_PATH instead
|
|
477
|
+
*/
|
|
478
|
+
`
|
|
479
|
+
});
|
|
480
|
+
}
|
|
437
481
|
sourceFile.saveSync();
|
|
438
482
|
}
|
|
439
483
|
};
|
|
@@ -799,6 +843,9 @@ function getTypeScriptType(schemaOrType, config, formatOrNullable, isNullable, c
|
|
|
799
843
|
}
|
|
800
844
|
switch (schema.type) {
|
|
801
845
|
case "string":
|
|
846
|
+
if (schema.enum) {
|
|
847
|
+
return schema.enum.map((value) => typeof value === "string" ? `'${escapeString(value)}'` : String(value)).join(" | ");
|
|
848
|
+
}
|
|
802
849
|
if (schema.format === "date" || schema.format === "date-time") {
|
|
803
850
|
const dateType = config.options.dateType === "Date" ? "Date" : "string";
|
|
804
851
|
return nullableType(dateType, nullable);
|
|
@@ -830,6 +877,10 @@ function nullableType(type, isNullable) {
|
|
|
830
877
|
return type + (isNullable ? " | null" : "");
|
|
831
878
|
}
|
|
832
879
|
__name(nullableType, "nullableType");
|
|
880
|
+
function escapeString(str) {
|
|
881
|
+
return str.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
|
|
882
|
+
}
|
|
883
|
+
__name(escapeString, "escapeString");
|
|
833
884
|
|
|
834
885
|
// src/lib/generators/service/service-method/service-method-body.generator.ts
|
|
835
886
|
var ServiceMethodBodyGenerator = class {
|
|
@@ -1695,6 +1746,8 @@ var ServiceGenerator = class {
|
|
|
1695
1746
|
});
|
|
1696
1747
|
}
|
|
1697
1748
|
addImports(sourceFile, usedTypes) {
|
|
1749
|
+
const clientName = this.config.clientName || "DEFAULT";
|
|
1750
|
+
const upperCaseClientName = clientName.toUpperCase().replace(/[^A-Z0-9]/g, "_");
|
|
1698
1751
|
sourceFile.addImportDeclarations([
|
|
1699
1752
|
{
|
|
1700
1753
|
namedImports: [
|
|
@@ -1722,11 +1775,15 @@ var ServiceGenerator = class {
|
|
|
1722
1775
|
},
|
|
1723
1776
|
{
|
|
1724
1777
|
namedImports: [
|
|
1725
|
-
|
|
1778
|
+
`${upperCaseClientName}_BASE_PATH`,
|
|
1779
|
+
`${upperCaseClientName}_HTTP_CLIENT`
|
|
1726
1780
|
],
|
|
1727
1781
|
moduleSpecifier: "../tokens"
|
|
1728
1782
|
}
|
|
1729
1783
|
]);
|
|
1784
|
+
if (!this.config.clientName) {
|
|
1785
|
+
sourceFile.getImportDeclaration("../tokens")?.addNamedImport("BASE_PATH");
|
|
1786
|
+
}
|
|
1730
1787
|
if (usedTypes.size > 0) {
|
|
1731
1788
|
sourceFile.addImportDeclaration({
|
|
1732
1789
|
namedImports: Array.from(usedTypes).sort(),
|
|
@@ -1736,6 +1793,8 @@ var ServiceGenerator = class {
|
|
|
1736
1793
|
}
|
|
1737
1794
|
addServiceClass(sourceFile, controllerName, operations) {
|
|
1738
1795
|
const className = `${controllerName}Service`;
|
|
1796
|
+
const clientName = this.config.clientName || "DEFAULT";
|
|
1797
|
+
const upperCaseClientName = clientName.toUpperCase().replace(/[^A-Z0-9]/g, "_");
|
|
1739
1798
|
sourceFile.insertText(0, SERVICE_GENERATOR_HEADER_COMMENT(controllerName));
|
|
1740
1799
|
const serviceClass = sourceFile.addClass({
|
|
1741
1800
|
name: className,
|
|
@@ -1754,14 +1813,14 @@ var ServiceGenerator = class {
|
|
|
1754
1813
|
type: "HttpClient",
|
|
1755
1814
|
scope: import_ts_morph3.Scope.Private,
|
|
1756
1815
|
isReadonly: true,
|
|
1757
|
-
initializer:
|
|
1816
|
+
initializer: `inject(${upperCaseClientName}_HTTP_CLIENT, { optional: true }) ?? inject(HttpClient)`
|
|
1758
1817
|
});
|
|
1759
1818
|
serviceClass.addProperty({
|
|
1760
1819
|
name: "basePath",
|
|
1761
1820
|
type: "string",
|
|
1762
1821
|
scope: import_ts_morph3.Scope.Private,
|
|
1763
1822
|
isReadonly: true,
|
|
1764
|
-
initializer:
|
|
1823
|
+
initializer: `inject(${upperCaseClientName}_BASE_PATH)`
|
|
1765
1824
|
});
|
|
1766
1825
|
operations.forEach((operation) => {
|
|
1767
1826
|
this.methodGenerator.addServiceMethod(serviceClass, operation);
|
|
@@ -1825,24 +1884,34 @@ var ProviderGenerator = class {
|
|
|
1825
1884
|
overwrite: true
|
|
1826
1885
|
});
|
|
1827
1886
|
sourceFile.insertText(0, PROVIDER_GENERATOR_HEADER_COMMENT);
|
|
1887
|
+
const clientName = this.config.clientName || "Default";
|
|
1888
|
+
const pascalClientName = this.pascalCase(clientName);
|
|
1889
|
+
const upperCaseClientName = clientName.toUpperCase().replace(/[^A-Z0-9]/g, "_");
|
|
1828
1890
|
sourceFile.addImportDeclarations([
|
|
1829
1891
|
{
|
|
1830
1892
|
namedImports: [
|
|
1831
1893
|
"EnvironmentProviders",
|
|
1832
1894
|
"Provider",
|
|
1833
|
-
"makeEnvironmentProviders"
|
|
1895
|
+
"makeEnvironmentProviders",
|
|
1896
|
+
"Type",
|
|
1897
|
+
"Injector",
|
|
1898
|
+
"inject"
|
|
1834
1899
|
],
|
|
1835
1900
|
moduleSpecifier: "@angular/core"
|
|
1836
1901
|
},
|
|
1837
1902
|
{
|
|
1838
1903
|
namedImports: [
|
|
1839
|
-
"
|
|
1904
|
+
"HttpClient",
|
|
1905
|
+
"HttpInterceptor",
|
|
1906
|
+
"HttpHandler",
|
|
1907
|
+
"HttpRequest"
|
|
1840
1908
|
],
|
|
1841
1909
|
moduleSpecifier: "@angular/common/http"
|
|
1842
1910
|
},
|
|
1843
1911
|
{
|
|
1844
1912
|
namedImports: [
|
|
1845
|
-
|
|
1913
|
+
`${upperCaseClientName}_BASE_PATH`,
|
|
1914
|
+
`${upperCaseClientName}_HTTP_CLIENT`
|
|
1846
1915
|
],
|
|
1847
1916
|
moduleSpecifier: "./tokens"
|
|
1848
1917
|
}
|
|
@@ -1856,10 +1925,10 @@ var ProviderGenerator = class {
|
|
|
1856
1925
|
});
|
|
1857
1926
|
}
|
|
1858
1927
|
sourceFile.addInterface({
|
|
1859
|
-
name:
|
|
1928
|
+
name: `${pascalClientName}Config`,
|
|
1860
1929
|
isExported: true,
|
|
1861
1930
|
docs: [
|
|
1862
|
-
|
|
1931
|
+
`Configuration options for ${clientName} API client`
|
|
1863
1932
|
],
|
|
1864
1933
|
properties: [
|
|
1865
1934
|
{
|
|
@@ -1869,6 +1938,14 @@ var ProviderGenerator = class {
|
|
|
1869
1938
|
"Base API URL"
|
|
1870
1939
|
]
|
|
1871
1940
|
},
|
|
1941
|
+
{
|
|
1942
|
+
name: "interceptors",
|
|
1943
|
+
type: "Type<HttpInterceptor>[]",
|
|
1944
|
+
hasQuestionToken: true,
|
|
1945
|
+
docs: [
|
|
1946
|
+
"HTTP interceptors to apply to this client's requests"
|
|
1947
|
+
]
|
|
1948
|
+
},
|
|
1872
1949
|
{
|
|
1873
1950
|
name: "enableDateTransform",
|
|
1874
1951
|
type: "boolean",
|
|
@@ -1879,105 +1956,102 @@ var ProviderGenerator = class {
|
|
|
1879
1956
|
}
|
|
1880
1957
|
]
|
|
1881
1958
|
});
|
|
1882
|
-
this.
|
|
1883
|
-
this.
|
|
1959
|
+
this.addInterceptorChainHelper(sourceFile);
|
|
1960
|
+
this.addClientProviderFunction(sourceFile, pascalClientName, upperCaseClientName);
|
|
1884
1961
|
sourceFile.saveSync();
|
|
1885
1962
|
}
|
|
1886
|
-
|
|
1887
|
-
const hasDateInterceptor = this.config.options.dateType === "Date";
|
|
1888
|
-
const functionBody = `
|
|
1889
|
-
const providers: Provider[] = [
|
|
1890
|
-
// Base path token
|
|
1891
|
-
{
|
|
1892
|
-
provide: BASE_PATH,
|
|
1893
|
-
useValue: config.basePath
|
|
1894
|
-
}
|
|
1895
|
-
];
|
|
1896
|
-
|
|
1897
|
-
${hasDateInterceptor ? `// Add date interceptor if enabled (default: true)
|
|
1898
|
-
if (config.enableDateTransform !== false) {
|
|
1899
|
-
providers.push({
|
|
1900
|
-
provide: HTTP_INTERCEPTORS,
|
|
1901
|
-
useClass: DateInterceptor,
|
|
1902
|
-
multi: true
|
|
1903
|
-
});
|
|
1904
|
-
}` : `// Date transformation not available (dateType: 'string' was used in generation)`}
|
|
1905
|
-
|
|
1906
|
-
return makeEnvironmentProviders(providers);`;
|
|
1963
|
+
addInterceptorChainHelper(sourceFile) {
|
|
1907
1964
|
sourceFile.addFunction({
|
|
1908
|
-
name: "
|
|
1909
|
-
isExported: true,
|
|
1965
|
+
name: "createHttpClientWithInterceptors",
|
|
1910
1966
|
docs: [
|
|
1911
|
-
"
|
|
1912
|
-
"",
|
|
1913
|
-
"@example",
|
|
1914
|
-
"```typescript",
|
|
1915
|
-
"// In your app.config.ts",
|
|
1916
|
-
"import { provideNgOpenapi } from './api/providers';",
|
|
1917
|
-
"",
|
|
1918
|
-
"export const appConfig: ApplicationConfig = {",
|
|
1919
|
-
" providers: [",
|
|
1920
|
-
" provideNgOpenapi({",
|
|
1921
|
-
" basePath: 'https://api.example.com'",
|
|
1922
|
-
" }),",
|
|
1923
|
-
" // other providers...",
|
|
1924
|
-
" ]",
|
|
1925
|
-
"};",
|
|
1926
|
-
"```"
|
|
1967
|
+
"Creates an HttpClient with a custom interceptor chain"
|
|
1927
1968
|
],
|
|
1928
1969
|
parameters: [
|
|
1929
1970
|
{
|
|
1930
|
-
name: "
|
|
1931
|
-
type: "
|
|
1971
|
+
name: "baseClient",
|
|
1972
|
+
type: "HttpClient"
|
|
1973
|
+
},
|
|
1974
|
+
{
|
|
1975
|
+
name: "interceptors",
|
|
1976
|
+
type: "HttpInterceptor[]"
|
|
1932
1977
|
}
|
|
1933
1978
|
],
|
|
1934
|
-
returnType: "
|
|
1935
|
-
statements:
|
|
1979
|
+
returnType: "HttpClient",
|
|
1980
|
+
statements: `
|
|
1981
|
+
if (!interceptors.length) {
|
|
1982
|
+
return baseClient;
|
|
1983
|
+
}
|
|
1984
|
+
|
|
1985
|
+
// Create a custom handler that applies interceptors in sequence
|
|
1986
|
+
let handler = baseClient.handler;
|
|
1987
|
+
|
|
1988
|
+
// Apply interceptors in reverse order (last interceptor wraps the original handler)
|
|
1989
|
+
for (let i = interceptors.length - 1; i >= 0; i--) {
|
|
1990
|
+
const currentHandler = handler;
|
|
1991
|
+
const interceptor = interceptors[i];
|
|
1992
|
+
|
|
1993
|
+
handler = {
|
|
1994
|
+
handle: (req: HttpRequest<any>) => interceptor.intercept(req, currentHandler)
|
|
1995
|
+
};
|
|
1996
|
+
}
|
|
1997
|
+
|
|
1998
|
+
// Return a new HttpClient with the custom handler
|
|
1999
|
+
return new (baseClient.constructor as any)(handler);`
|
|
1936
2000
|
});
|
|
1937
2001
|
}
|
|
1938
|
-
|
|
2002
|
+
addClientProviderFunction(sourceFile, pascalClientName, upperCaseClientName) {
|
|
1939
2003
|
const hasDateInterceptor = this.config.options.dateType === "Date";
|
|
1940
2004
|
const functionBody = `
|
|
1941
|
-
const providers: Provider[] = [
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
providers.push({
|
|
1946
|
-
provide: BASE_PATH,
|
|
2005
|
+
const providers: Provider[] = [
|
|
2006
|
+
// Base path token
|
|
2007
|
+
{
|
|
2008
|
+
provide: ${upperCaseClientName}_BASE_PATH,
|
|
1947
2009
|
useValue: config.basePath
|
|
1948
|
-
}
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
if (config.
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
2010
|
+
},
|
|
2011
|
+
|
|
2012
|
+
// HTTP client with custom interceptors
|
|
2013
|
+
{
|
|
2014
|
+
provide: ${upperCaseClientName}_HTTP_CLIENT,
|
|
2015
|
+
useFactory: (baseClient: HttpClient, injector: Injector) => {
|
|
2016
|
+
const interceptorInstances: HttpInterceptor[] = [];
|
|
2017
|
+
|
|
2018
|
+
// Add custom interceptors
|
|
2019
|
+
if (config.interceptors?.length) {
|
|
2020
|
+
config.interceptors.forEach(interceptorClass => {
|
|
2021
|
+
interceptorInstances.push(injector.get(interceptorClass));
|
|
2022
|
+
});
|
|
2023
|
+
}
|
|
2024
|
+
|
|
2025
|
+
${hasDateInterceptor ? `
|
|
2026
|
+
// Add date interceptor if enabled (default: true)
|
|
2027
|
+
if (config.enableDateTransform !== false) {
|
|
2028
|
+
interceptorInstances.push(injector.get(DateInterceptor));
|
|
2029
|
+
}` : ""}
|
|
2030
|
+
|
|
2031
|
+
return createHttpClientWithInterceptors(baseClient, interceptorInstances);
|
|
2032
|
+
},
|
|
2033
|
+
deps: [HttpClient, Injector]
|
|
2034
|
+
}
|
|
2035
|
+
];
|
|
1964
2036
|
|
|
1965
2037
|
return makeEnvironmentProviders(providers);`;
|
|
1966
2038
|
sourceFile.addFunction({
|
|
1967
|
-
name:
|
|
2039
|
+
name: `provide${pascalClientName}`,
|
|
1968
2040
|
isExported: true,
|
|
1969
2041
|
docs: [
|
|
1970
|
-
|
|
2042
|
+
`Provides configuration for ${pascalClientName} API client`,
|
|
1971
2043
|
"",
|
|
1972
2044
|
"@example",
|
|
1973
2045
|
"```typescript",
|
|
1974
|
-
|
|
1975
|
-
|
|
2046
|
+
`// In your app.config.ts`,
|
|
2047
|
+
`import { provide${pascalClientName} } from './api/providers';`,
|
|
2048
|
+
`import { AuthInterceptor } from './interceptors/auth.interceptor';`,
|
|
1976
2049
|
"",
|
|
1977
2050
|
"export const appConfig: ApplicationConfig = {",
|
|
1978
2051
|
" providers: [",
|
|
1979
|
-
|
|
1980
|
-
" basePath:
|
|
2052
|
+
` provide${pascalClientName}({`,
|
|
2053
|
+
" basePath: 'https://api.example.com',",
|
|
2054
|
+
" interceptors: [AuthInterceptor]",
|
|
1981
2055
|
" }),",
|
|
1982
2056
|
" // other providers...",
|
|
1983
2057
|
" ]",
|
|
@@ -1987,16 +2061,16 @@ return makeEnvironmentProviders(providers);`;
|
|
|
1987
2061
|
parameters: [
|
|
1988
2062
|
{
|
|
1989
2063
|
name: "config",
|
|
1990
|
-
type: `
|
|
1991
|
-
basePath: string | (() => Promise<string>);
|
|
1992
|
-
enableDateTransform?: boolean;
|
|
1993
|
-
}`
|
|
2064
|
+
type: `${pascalClientName}Config`
|
|
1994
2065
|
}
|
|
1995
2066
|
],
|
|
1996
2067
|
returnType: "EnvironmentProviders",
|
|
1997
2068
|
statements: functionBody
|
|
1998
2069
|
});
|
|
1999
2070
|
}
|
|
2071
|
+
pascalCase(str) {
|
|
2072
|
+
return str.replace(/(?:^|[-_])([a-z])/g, (_, char) => char.toUpperCase());
|
|
2073
|
+
}
|
|
2000
2074
|
};
|
|
2001
2075
|
|
|
2002
2076
|
// src/lib/core/generator.ts
|
|
@@ -2026,7 +2100,7 @@ async function generateFromConfig(config) {
|
|
|
2026
2100
|
typeGenerator.generate();
|
|
2027
2101
|
console.log(`\u2705 TypeScript interfaces generated`);
|
|
2028
2102
|
if (generateServices) {
|
|
2029
|
-
const tokenGenerator = new TokenGenerator(project);
|
|
2103
|
+
const tokenGenerator = new TokenGenerator(project, config);
|
|
2030
2104
|
tokenGenerator.generate(outputPath);
|
|
2031
2105
|
if (config.options.dateType === "Date") {
|
|
2032
2106
|
const dateTransformer = new DateTransformerGenerator(project);
|
|
@@ -2059,6 +2133,94 @@ async function generateFromConfig(config) {
|
|
|
2059
2133
|
}
|
|
2060
2134
|
__name(generateFromConfig, "generateFromConfig");
|
|
2061
2135
|
|
|
2136
|
+
// package.json
|
|
2137
|
+
var package_default = {
|
|
2138
|
+
name: "ng-openapi",
|
|
2139
|
+
version: "0.0.22",
|
|
2140
|
+
description: "Generate Angular services and TypeScript types from OpenAPI/Swagger specifications",
|
|
2141
|
+
keywords: [
|
|
2142
|
+
"angular",
|
|
2143
|
+
"openapi",
|
|
2144
|
+
"swagger",
|
|
2145
|
+
"codegen",
|
|
2146
|
+
"typescript",
|
|
2147
|
+
"generator",
|
|
2148
|
+
"code-generator",
|
|
2149
|
+
"api",
|
|
2150
|
+
"rest",
|
|
2151
|
+
"http",
|
|
2152
|
+
"cli"
|
|
2153
|
+
],
|
|
2154
|
+
author: {
|
|
2155
|
+
name: "Tareq Jami",
|
|
2156
|
+
email: "info@jami-it.de",
|
|
2157
|
+
url: "http://tareqjami.de"
|
|
2158
|
+
},
|
|
2159
|
+
license: "MIT",
|
|
2160
|
+
homepage: "https://ng-openapi.dev/",
|
|
2161
|
+
bugs: {
|
|
2162
|
+
url: "https://github.com/ng-openapi/ng-openapi/issues"
|
|
2163
|
+
},
|
|
2164
|
+
repository: {
|
|
2165
|
+
type: "git",
|
|
2166
|
+
url: "git+https://github.com/ng-openapi/ng-openapi.git",
|
|
2167
|
+
directory: "packages/ng-openapi"
|
|
2168
|
+
},
|
|
2169
|
+
funding: {
|
|
2170
|
+
type: "github",
|
|
2171
|
+
url: "https://github.com/sponsors/ng-openapi"
|
|
2172
|
+
},
|
|
2173
|
+
main: "./index.cjs",
|
|
2174
|
+
module: "./index.js",
|
|
2175
|
+
types: "./index.d.ts",
|
|
2176
|
+
bin: {
|
|
2177
|
+
"ng-openapi": "./cli.cjs"
|
|
2178
|
+
},
|
|
2179
|
+
files: [
|
|
2180
|
+
"index.js",
|
|
2181
|
+
"index.cjs",
|
|
2182
|
+
"index.d.ts",
|
|
2183
|
+
"cli.cjs",
|
|
2184
|
+
"lib/**/*.js",
|
|
2185
|
+
"lib/**/*.cjs",
|
|
2186
|
+
"lib/**/*.d.ts",
|
|
2187
|
+
"README.md",
|
|
2188
|
+
"LICENSE",
|
|
2189
|
+
"CHANGELOG.md"
|
|
2190
|
+
],
|
|
2191
|
+
scripts: {
|
|
2192
|
+
prepublishOnly: "echo 'Build the package using: npm run build:ng-openapi from workspace root'",
|
|
2193
|
+
build: "tsup"
|
|
2194
|
+
},
|
|
2195
|
+
dependencies: {
|
|
2196
|
+
commander: "^14.0.0",
|
|
2197
|
+
"ts-morph": "^26.0.0",
|
|
2198
|
+
"ts-node": "^10.9.2",
|
|
2199
|
+
typescript: "^5.8.3",
|
|
2200
|
+
"@types/swagger-schema-official": "^2.0.25"
|
|
2201
|
+
},
|
|
2202
|
+
peerDependencies: {
|
|
2203
|
+
"@angular/core": ">=15",
|
|
2204
|
+
"@angular/common": ">=15"
|
|
2205
|
+
},
|
|
2206
|
+
peerDependenciesMeta: {
|
|
2207
|
+
"@angular/core": {
|
|
2208
|
+
optional: false
|
|
2209
|
+
},
|
|
2210
|
+
"@angular/common": {
|
|
2211
|
+
optional: false
|
|
2212
|
+
}
|
|
2213
|
+
},
|
|
2214
|
+
engines: {
|
|
2215
|
+
node: ">=18.0.0",
|
|
2216
|
+
npm: ">=8.0.0"
|
|
2217
|
+
},
|
|
2218
|
+
publishConfig: {
|
|
2219
|
+
access: "public",
|
|
2220
|
+
registry: "https://registry.npmjs.org/"
|
|
2221
|
+
}
|
|
2222
|
+
};
|
|
2223
|
+
|
|
2062
2224
|
// src/lib/cli.ts
|
|
2063
2225
|
var program = new import_commander.Command();
|
|
2064
2226
|
async function loadConfigFile(configPath) {
|
|
@@ -2085,17 +2247,19 @@ __name(loadConfigFile, "loadConfigFile");
|
|
|
2085
2247
|
async function generateFromOptions(options) {
|
|
2086
2248
|
try {
|
|
2087
2249
|
if (options.config) {
|
|
2088
|
-
const
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
const
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2250
|
+
const configPaths = Array.isArray(options.config) ? options.config : [
|
|
2251
|
+
options.config
|
|
2252
|
+
];
|
|
2253
|
+
for (const configPath of configPaths) {
|
|
2254
|
+
const config = await loadConfigFile(configPath);
|
|
2255
|
+
await generateFromConfig(config);
|
|
2256
|
+
console.log(`\u2728 Generated client: ${config.clientName || "default"}`);
|
|
2095
2257
|
}
|
|
2258
|
+
} else if (options.input) {
|
|
2096
2259
|
const config = {
|
|
2097
|
-
input:
|
|
2260
|
+
input: path8.resolve(options.input),
|
|
2098
2261
|
output: options.output || "./src/generated",
|
|
2262
|
+
clientName: options.clientName,
|
|
2099
2263
|
options: {
|
|
2100
2264
|
dateType: options.dateType || "Date",
|
|
2101
2265
|
enumStyle: "enum",
|
|
@@ -2109,14 +2273,14 @@ async function generateFromOptions(options) {
|
|
|
2109
2273
|
program.help();
|
|
2110
2274
|
process.exit(1);
|
|
2111
2275
|
}
|
|
2112
|
-
console.log("\u2728
|
|
2276
|
+
console.log("\u2728 All clients generated successfully!");
|
|
2113
2277
|
} catch (error) {
|
|
2114
2278
|
console.error("\u274C Generation failed:", error instanceof Error ? error.message : error);
|
|
2115
2279
|
process.exit(1);
|
|
2116
2280
|
}
|
|
2117
2281
|
}
|
|
2118
2282
|
__name(generateFromOptions, "generateFromOptions");
|
|
2119
|
-
program.name("ng-openapi").description("Generate Angular services and types from Swagger/OpenAPI spec").version(
|
|
2283
|
+
program.name("ng-openapi").description("Generate Angular services and types from Swagger/OpenAPI spec").version(package_default.version).option("-c, --config <path>", "Path to configuration file").option("-i, --input <path>", "Path to Swagger/OpenAPI specification file").option("-o, --output <path>", "Output directory", "./src/generated").option("--types-only", "Generate only TypeScript interfaces").option("--date-type <type>", "Date type to use (string | Date)", "Date").action(async (options) => {
|
|
2120
2284
|
await generateFromOptions(options);
|
|
2121
2285
|
});
|
|
2122
2286
|
program.command("generate").alias("gen").description("Generate code from Swagger specification").option("-c, --config <path>", "Path to configuration file").option("-i, --input <path>", "Path to Swagger/OpenAPI specification file").option("-o, --output <path>", "Output directory", "./src/generated").option("--types-only", "Generate only TypeScript interfaces").option("--date-type <type>", "Date type to use (string | Date)", "Date").action(async (options) => {
|
|
@@ -2131,4 +2295,8 @@ program.on("--help", () => {
|
|
|
2131
2295
|
console.log(" $ ng-openapi generate -i ./api.yaml --types-only");
|
|
2132
2296
|
});
|
|
2133
2297
|
program.parse();
|
|
2298
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
2299
|
+
0 && (module.exports = {
|
|
2300
|
+
generateFromOptions
|
|
2301
|
+
});
|
|
2134
2302
|
//# sourceMappingURL=cli.cjs.map
|
package/index.d.ts
CHANGED
|
@@ -21,12 +21,14 @@ interface TypeSchema {
|
|
|
21
21
|
$ref?: string;
|
|
22
22
|
items?: any;
|
|
23
23
|
nullable?: boolean;
|
|
24
|
+
enum?: Array<string | number>;
|
|
24
25
|
[key: string]: any;
|
|
25
26
|
}
|
|
26
27
|
|
|
27
28
|
interface GeneratorConfig {
|
|
28
29
|
input: string;
|
|
29
30
|
output: string;
|
|
31
|
+
clientName?: string;
|
|
30
32
|
options: {
|
|
31
33
|
dateType: "string" | "Date";
|
|
32
34
|
enumStyle: "enum" | "union";
|
package/index.js
CHANGED
|
@@ -441,9 +441,11 @@ var TypeGenerator = _TypeGenerator;
|
|
|
441
441
|
var import_ts_morph2 = require("ts-morph");
|
|
442
442
|
var path = __toESM(require("path"));
|
|
443
443
|
var _TokenGenerator = class _TokenGenerator {
|
|
444
|
-
constructor(project) {
|
|
444
|
+
constructor(project, config) {
|
|
445
445
|
__publicField(this, "project");
|
|
446
|
+
__publicField(this, "config");
|
|
446
447
|
this.project = project;
|
|
448
|
+
this.config = config;
|
|
447
449
|
}
|
|
448
450
|
generate(outputDir) {
|
|
449
451
|
const tokensDir = path.join(outputDir, "tokens");
|
|
@@ -457,23 +459,55 @@ var _TokenGenerator = class _TokenGenerator {
|
|
|
457
459
|
],
|
|
458
460
|
moduleSpecifier: "@angular/core"
|
|
459
461
|
});
|
|
462
|
+
const clientName = this.config.clientName || "DEFAULT";
|
|
463
|
+
const upperCaseClientName = clientName.toUpperCase().replace(/[^A-Z0-9]/g, "_");
|
|
460
464
|
sourceFile.addVariableStatement({
|
|
461
465
|
isExported: true,
|
|
462
466
|
declarationKind: import_ts_morph2.VariableDeclarationKind.Const,
|
|
463
467
|
declarations: [
|
|
464
468
|
{
|
|
465
|
-
name:
|
|
466
|
-
initializer: `new InjectionToken<string>('
|
|
469
|
+
name: `${upperCaseClientName}_BASE_PATH`,
|
|
470
|
+
initializer: `new InjectionToken<string>('${upperCaseClientName}_BASE_PATH', {
|
|
467
471
|
providedIn: 'root',
|
|
468
|
-
factory: () => '/api',
|
|
472
|
+
factory: () => '/api',
|
|
469
473
|
})`
|
|
470
474
|
}
|
|
471
475
|
],
|
|
472
476
|
leadingTrivia: `/**
|
|
473
|
-
*
|
|
477
|
+
* Base path token for ${clientName} client
|
|
478
|
+
*/
|
|
479
|
+
`
|
|
480
|
+
});
|
|
481
|
+
sourceFile.addVariableStatement({
|
|
482
|
+
isExported: true,
|
|
483
|
+
declarationKind: import_ts_morph2.VariableDeclarationKind.Const,
|
|
484
|
+
declarations: [
|
|
485
|
+
{
|
|
486
|
+
name: `${upperCaseClientName}_HTTP_CLIENT`,
|
|
487
|
+
initializer: `new InjectionToken<HttpClient>('${upperCaseClientName}_HTTP_CLIENT')`
|
|
488
|
+
}
|
|
489
|
+
],
|
|
490
|
+
leadingTrivia: `/**
|
|
491
|
+
* HTTP client token for ${clientName} client
|
|
474
492
|
*/
|
|
475
493
|
`
|
|
476
494
|
});
|
|
495
|
+
if (!this.config.clientName) {
|
|
496
|
+
sourceFile.addVariableStatement({
|
|
497
|
+
isExported: true,
|
|
498
|
+
declarationKind: import_ts_morph2.VariableDeclarationKind.Const,
|
|
499
|
+
declarations: [
|
|
500
|
+
{
|
|
501
|
+
name: "BASE_PATH",
|
|
502
|
+
initializer: `${upperCaseClientName}_BASE_PATH`
|
|
503
|
+
}
|
|
504
|
+
],
|
|
505
|
+
leadingTrivia: `/**
|
|
506
|
+
* @deprecated Use ${upperCaseClientName}_BASE_PATH instead
|
|
507
|
+
*/
|
|
508
|
+
`
|
|
509
|
+
});
|
|
510
|
+
}
|
|
477
511
|
sourceFile.saveSync();
|
|
478
512
|
}
|
|
479
513
|
};
|
|
@@ -838,6 +872,9 @@ function getTypeScriptType(schemaOrType, config, formatOrNullable, isNullable, c
|
|
|
838
872
|
}
|
|
839
873
|
switch (schema.type) {
|
|
840
874
|
case "string":
|
|
875
|
+
if (schema.enum) {
|
|
876
|
+
return schema.enum.map((value) => typeof value === "string" ? `'${escapeString(value)}'` : String(value)).join(" | ");
|
|
877
|
+
}
|
|
841
878
|
if (schema.format === "date" || schema.format === "date-time") {
|
|
842
879
|
const dateType = config.options.dateType === "Date" ? "Date" : "string";
|
|
843
880
|
return nullableType(dateType, nullable);
|
|
@@ -869,6 +906,10 @@ function nullableType(type, isNullable) {
|
|
|
869
906
|
return type + (isNullable ? " | null" : "");
|
|
870
907
|
}
|
|
871
908
|
__name(nullableType, "nullableType");
|
|
909
|
+
function escapeString(str) {
|
|
910
|
+
return str.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
|
|
911
|
+
}
|
|
912
|
+
__name(escapeString, "escapeString");
|
|
872
913
|
|
|
873
914
|
// src/lib/generators/service/service-method/service-method-body.generator.ts
|
|
874
915
|
var _ServiceMethodBodyGenerator = class _ServiceMethodBodyGenerator {
|
|
@@ -1739,6 +1780,9 @@ var _ServiceGenerator = class _ServiceGenerator {
|
|
|
1739
1780
|
});
|
|
1740
1781
|
}
|
|
1741
1782
|
addImports(sourceFile, usedTypes) {
|
|
1783
|
+
var _a;
|
|
1784
|
+
const clientName = this.config.clientName || "DEFAULT";
|
|
1785
|
+
const upperCaseClientName = clientName.toUpperCase().replace(/[^A-Z0-9]/g, "_");
|
|
1742
1786
|
sourceFile.addImportDeclarations([
|
|
1743
1787
|
{
|
|
1744
1788
|
namedImports: [
|
|
@@ -1766,11 +1810,15 @@ var _ServiceGenerator = class _ServiceGenerator {
|
|
|
1766
1810
|
},
|
|
1767
1811
|
{
|
|
1768
1812
|
namedImports: [
|
|
1769
|
-
|
|
1813
|
+
`${upperCaseClientName}_BASE_PATH`,
|
|
1814
|
+
`${upperCaseClientName}_HTTP_CLIENT`
|
|
1770
1815
|
],
|
|
1771
1816
|
moduleSpecifier: "../tokens"
|
|
1772
1817
|
}
|
|
1773
1818
|
]);
|
|
1819
|
+
if (!this.config.clientName) {
|
|
1820
|
+
(_a = sourceFile.getImportDeclaration("../tokens")) == null ? void 0 : _a.addNamedImport("BASE_PATH");
|
|
1821
|
+
}
|
|
1774
1822
|
if (usedTypes.size > 0) {
|
|
1775
1823
|
sourceFile.addImportDeclaration({
|
|
1776
1824
|
namedImports: Array.from(usedTypes).sort(),
|
|
@@ -1780,6 +1828,8 @@ var _ServiceGenerator = class _ServiceGenerator {
|
|
|
1780
1828
|
}
|
|
1781
1829
|
addServiceClass(sourceFile, controllerName, operations) {
|
|
1782
1830
|
const className = `${controllerName}Service`;
|
|
1831
|
+
const clientName = this.config.clientName || "DEFAULT";
|
|
1832
|
+
const upperCaseClientName = clientName.toUpperCase().replace(/[^A-Z0-9]/g, "_");
|
|
1783
1833
|
sourceFile.insertText(0, SERVICE_GENERATOR_HEADER_COMMENT(controllerName));
|
|
1784
1834
|
const serviceClass = sourceFile.addClass({
|
|
1785
1835
|
name: className,
|
|
@@ -1798,14 +1848,14 @@ var _ServiceGenerator = class _ServiceGenerator {
|
|
|
1798
1848
|
type: "HttpClient",
|
|
1799
1849
|
scope: import_ts_morph3.Scope.Private,
|
|
1800
1850
|
isReadonly: true,
|
|
1801
|
-
initializer:
|
|
1851
|
+
initializer: `inject(${upperCaseClientName}_HTTP_CLIENT, { optional: true }) ?? inject(HttpClient)`
|
|
1802
1852
|
});
|
|
1803
1853
|
serviceClass.addProperty({
|
|
1804
1854
|
name: "basePath",
|
|
1805
1855
|
type: "string",
|
|
1806
1856
|
scope: import_ts_morph3.Scope.Private,
|
|
1807
1857
|
isReadonly: true,
|
|
1808
|
-
initializer:
|
|
1858
|
+
initializer: `inject(${upperCaseClientName}_BASE_PATH)`
|
|
1809
1859
|
});
|
|
1810
1860
|
operations.forEach((operation) => {
|
|
1811
1861
|
this.methodGenerator.addServiceMethod(serviceClass, operation);
|
|
@@ -1867,24 +1917,34 @@ var _ProviderGenerator = class _ProviderGenerator {
|
|
|
1867
1917
|
overwrite: true
|
|
1868
1918
|
});
|
|
1869
1919
|
sourceFile.insertText(0, PROVIDER_GENERATOR_HEADER_COMMENT);
|
|
1920
|
+
const clientName = this.config.clientName || "Default";
|
|
1921
|
+
const pascalClientName = this.pascalCase(clientName);
|
|
1922
|
+
const upperCaseClientName = clientName.toUpperCase().replace(/[^A-Z0-9]/g, "_");
|
|
1870
1923
|
sourceFile.addImportDeclarations([
|
|
1871
1924
|
{
|
|
1872
1925
|
namedImports: [
|
|
1873
1926
|
"EnvironmentProviders",
|
|
1874
1927
|
"Provider",
|
|
1875
|
-
"makeEnvironmentProviders"
|
|
1928
|
+
"makeEnvironmentProviders",
|
|
1929
|
+
"Type",
|
|
1930
|
+
"Injector",
|
|
1931
|
+
"inject"
|
|
1876
1932
|
],
|
|
1877
1933
|
moduleSpecifier: "@angular/core"
|
|
1878
1934
|
},
|
|
1879
1935
|
{
|
|
1880
1936
|
namedImports: [
|
|
1881
|
-
"
|
|
1937
|
+
"HttpClient",
|
|
1938
|
+
"HttpInterceptor",
|
|
1939
|
+
"HttpHandler",
|
|
1940
|
+
"HttpRequest"
|
|
1882
1941
|
],
|
|
1883
1942
|
moduleSpecifier: "@angular/common/http"
|
|
1884
1943
|
},
|
|
1885
1944
|
{
|
|
1886
1945
|
namedImports: [
|
|
1887
|
-
|
|
1946
|
+
`${upperCaseClientName}_BASE_PATH`,
|
|
1947
|
+
`${upperCaseClientName}_HTTP_CLIENT`
|
|
1888
1948
|
],
|
|
1889
1949
|
moduleSpecifier: "./tokens"
|
|
1890
1950
|
}
|
|
@@ -1898,10 +1958,10 @@ var _ProviderGenerator = class _ProviderGenerator {
|
|
|
1898
1958
|
});
|
|
1899
1959
|
}
|
|
1900
1960
|
sourceFile.addInterface({
|
|
1901
|
-
name:
|
|
1961
|
+
name: `${pascalClientName}Config`,
|
|
1902
1962
|
isExported: true,
|
|
1903
1963
|
docs: [
|
|
1904
|
-
|
|
1964
|
+
`Configuration options for ${clientName} API client`
|
|
1905
1965
|
],
|
|
1906
1966
|
properties: [
|
|
1907
1967
|
{
|
|
@@ -1911,6 +1971,14 @@ var _ProviderGenerator = class _ProviderGenerator {
|
|
|
1911
1971
|
"Base API URL"
|
|
1912
1972
|
]
|
|
1913
1973
|
},
|
|
1974
|
+
{
|
|
1975
|
+
name: "interceptors",
|
|
1976
|
+
type: "Type<HttpInterceptor>[]",
|
|
1977
|
+
hasQuestionToken: true,
|
|
1978
|
+
docs: [
|
|
1979
|
+
"HTTP interceptors to apply to this client's requests"
|
|
1980
|
+
]
|
|
1981
|
+
},
|
|
1914
1982
|
{
|
|
1915
1983
|
name: "enableDateTransform",
|
|
1916
1984
|
type: "boolean",
|
|
@@ -1921,105 +1989,102 @@ var _ProviderGenerator = class _ProviderGenerator {
|
|
|
1921
1989
|
}
|
|
1922
1990
|
]
|
|
1923
1991
|
});
|
|
1924
|
-
this.
|
|
1925
|
-
this.
|
|
1992
|
+
this.addInterceptorChainHelper(sourceFile);
|
|
1993
|
+
this.addClientProviderFunction(sourceFile, pascalClientName, upperCaseClientName);
|
|
1926
1994
|
sourceFile.saveSync();
|
|
1927
1995
|
}
|
|
1928
|
-
|
|
1929
|
-
const hasDateInterceptor = this.config.options.dateType === "Date";
|
|
1930
|
-
const functionBody = `
|
|
1931
|
-
const providers: Provider[] = [
|
|
1932
|
-
// Base path token
|
|
1933
|
-
{
|
|
1934
|
-
provide: BASE_PATH,
|
|
1935
|
-
useValue: config.basePath
|
|
1936
|
-
}
|
|
1937
|
-
];
|
|
1938
|
-
|
|
1939
|
-
${hasDateInterceptor ? `// Add date interceptor if enabled (default: true)
|
|
1940
|
-
if (config.enableDateTransform !== false) {
|
|
1941
|
-
providers.push({
|
|
1942
|
-
provide: HTTP_INTERCEPTORS,
|
|
1943
|
-
useClass: DateInterceptor,
|
|
1944
|
-
multi: true
|
|
1945
|
-
});
|
|
1946
|
-
}` : `// Date transformation not available (dateType: 'string' was used in generation)`}
|
|
1947
|
-
|
|
1948
|
-
return makeEnvironmentProviders(providers);`;
|
|
1996
|
+
addInterceptorChainHelper(sourceFile) {
|
|
1949
1997
|
sourceFile.addFunction({
|
|
1950
|
-
name: "
|
|
1951
|
-
isExported: true,
|
|
1998
|
+
name: "createHttpClientWithInterceptors",
|
|
1952
1999
|
docs: [
|
|
1953
|
-
"
|
|
1954
|
-
"",
|
|
1955
|
-
"@example",
|
|
1956
|
-
"```typescript",
|
|
1957
|
-
"// In your app.config.ts",
|
|
1958
|
-
"import { provideNgOpenapi } from './api/providers';",
|
|
1959
|
-
"",
|
|
1960
|
-
"export const appConfig: ApplicationConfig = {",
|
|
1961
|
-
" providers: [",
|
|
1962
|
-
" provideNgOpenapi({",
|
|
1963
|
-
" basePath: 'https://api.example.com'",
|
|
1964
|
-
" }),",
|
|
1965
|
-
" // other providers...",
|
|
1966
|
-
" ]",
|
|
1967
|
-
"};",
|
|
1968
|
-
"```"
|
|
2000
|
+
"Creates an HttpClient with a custom interceptor chain"
|
|
1969
2001
|
],
|
|
1970
2002
|
parameters: [
|
|
1971
2003
|
{
|
|
1972
|
-
name: "
|
|
1973
|
-
type: "
|
|
2004
|
+
name: "baseClient",
|
|
2005
|
+
type: "HttpClient"
|
|
2006
|
+
},
|
|
2007
|
+
{
|
|
2008
|
+
name: "interceptors",
|
|
2009
|
+
type: "HttpInterceptor[]"
|
|
1974
2010
|
}
|
|
1975
2011
|
],
|
|
1976
|
-
returnType: "
|
|
1977
|
-
statements:
|
|
2012
|
+
returnType: "HttpClient",
|
|
2013
|
+
statements: `
|
|
2014
|
+
if (!interceptors.length) {
|
|
2015
|
+
return baseClient;
|
|
2016
|
+
}
|
|
2017
|
+
|
|
2018
|
+
// Create a custom handler that applies interceptors in sequence
|
|
2019
|
+
let handler = baseClient.handler;
|
|
2020
|
+
|
|
2021
|
+
// Apply interceptors in reverse order (last interceptor wraps the original handler)
|
|
2022
|
+
for (let i = interceptors.length - 1; i >= 0; i--) {
|
|
2023
|
+
const currentHandler = handler;
|
|
2024
|
+
const interceptor = interceptors[i];
|
|
2025
|
+
|
|
2026
|
+
handler = {
|
|
2027
|
+
handle: (req: HttpRequest<any>) => interceptor.intercept(req, currentHandler)
|
|
2028
|
+
};
|
|
2029
|
+
}
|
|
2030
|
+
|
|
2031
|
+
// Return a new HttpClient with the custom handler
|
|
2032
|
+
return new (baseClient.constructor as any)(handler);`
|
|
1978
2033
|
});
|
|
1979
2034
|
}
|
|
1980
|
-
|
|
2035
|
+
addClientProviderFunction(sourceFile, pascalClientName, upperCaseClientName) {
|
|
1981
2036
|
const hasDateInterceptor = this.config.options.dateType === "Date";
|
|
1982
2037
|
const functionBody = `
|
|
1983
|
-
const providers: Provider[] = [
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
providers.push({
|
|
1988
|
-
provide: BASE_PATH,
|
|
2038
|
+
const providers: Provider[] = [
|
|
2039
|
+
// Base path token
|
|
2040
|
+
{
|
|
2041
|
+
provide: ${upperCaseClientName}_BASE_PATH,
|
|
1989
2042
|
useValue: config.basePath
|
|
1990
|
-
}
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
if (config.
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2043
|
+
},
|
|
2044
|
+
|
|
2045
|
+
// HTTP client with custom interceptors
|
|
2046
|
+
{
|
|
2047
|
+
provide: ${upperCaseClientName}_HTTP_CLIENT,
|
|
2048
|
+
useFactory: (baseClient: HttpClient, injector: Injector) => {
|
|
2049
|
+
const interceptorInstances: HttpInterceptor[] = [];
|
|
2050
|
+
|
|
2051
|
+
// Add custom interceptors
|
|
2052
|
+
if (config.interceptors?.length) {
|
|
2053
|
+
config.interceptors.forEach(interceptorClass => {
|
|
2054
|
+
interceptorInstances.push(injector.get(interceptorClass));
|
|
2055
|
+
});
|
|
2056
|
+
}
|
|
2057
|
+
|
|
2058
|
+
${hasDateInterceptor ? `
|
|
2059
|
+
// Add date interceptor if enabled (default: true)
|
|
2060
|
+
if (config.enableDateTransform !== false) {
|
|
2061
|
+
interceptorInstances.push(injector.get(DateInterceptor));
|
|
2062
|
+
}` : ""}
|
|
2063
|
+
|
|
2064
|
+
return createHttpClientWithInterceptors(baseClient, interceptorInstances);
|
|
2065
|
+
},
|
|
2066
|
+
deps: [HttpClient, Injector]
|
|
2067
|
+
}
|
|
2068
|
+
];
|
|
2006
2069
|
|
|
2007
2070
|
return makeEnvironmentProviders(providers);`;
|
|
2008
2071
|
sourceFile.addFunction({
|
|
2009
|
-
name:
|
|
2072
|
+
name: `provide${pascalClientName}`,
|
|
2010
2073
|
isExported: true,
|
|
2011
2074
|
docs: [
|
|
2012
|
-
|
|
2075
|
+
`Provides configuration for ${pascalClientName} API client`,
|
|
2013
2076
|
"",
|
|
2014
2077
|
"@example",
|
|
2015
2078
|
"```typescript",
|
|
2016
|
-
|
|
2017
|
-
|
|
2079
|
+
`// In your app.config.ts`,
|
|
2080
|
+
`import { provide${pascalClientName} } from './api/providers';`,
|
|
2081
|
+
`import { AuthInterceptor } from './interceptors/auth.interceptor';`,
|
|
2018
2082
|
"",
|
|
2019
2083
|
"export const appConfig: ApplicationConfig = {",
|
|
2020
2084
|
" providers: [",
|
|
2021
|
-
|
|
2022
|
-
" basePath:
|
|
2085
|
+
` provide${pascalClientName}({`,
|
|
2086
|
+
" basePath: 'https://api.example.com',",
|
|
2087
|
+
" interceptors: [AuthInterceptor]",
|
|
2023
2088
|
" }),",
|
|
2024
2089
|
" // other providers...",
|
|
2025
2090
|
" ]",
|
|
@@ -2029,16 +2094,16 @@ return makeEnvironmentProviders(providers);`;
|
|
|
2029
2094
|
parameters: [
|
|
2030
2095
|
{
|
|
2031
2096
|
name: "config",
|
|
2032
|
-
type: `
|
|
2033
|
-
basePath: string | (() => Promise<string>);
|
|
2034
|
-
enableDateTransform?: boolean;
|
|
2035
|
-
}`
|
|
2097
|
+
type: `${pascalClientName}Config`
|
|
2036
2098
|
}
|
|
2037
2099
|
],
|
|
2038
2100
|
returnType: "EnvironmentProviders",
|
|
2039
2101
|
statements: functionBody
|
|
2040
2102
|
});
|
|
2041
2103
|
}
|
|
2104
|
+
pascalCase(str) {
|
|
2105
|
+
return str.replace(/(?:^|[-_])([a-z])/g, (_, char) => char.toUpperCase());
|
|
2106
|
+
}
|
|
2042
2107
|
};
|
|
2043
2108
|
__name(_ProviderGenerator, "ProviderGenerator");
|
|
2044
2109
|
var ProviderGenerator = _ProviderGenerator;
|
|
@@ -2071,7 +2136,7 @@ function generateFromConfig(config) {
|
|
|
2071
2136
|
typeGenerator.generate();
|
|
2072
2137
|
console.log(`\u2705 TypeScript interfaces generated`);
|
|
2073
2138
|
if (generateServices) {
|
|
2074
|
-
const tokenGenerator = new TokenGenerator(project);
|
|
2139
|
+
const tokenGenerator = new TokenGenerator(project, config);
|
|
2075
2140
|
tokenGenerator.generate(outputPath);
|
|
2076
2141
|
if (config.options.dateType === "Date") {
|
|
2077
2142
|
const dateTransformer = new DateTransformerGenerator(project);
|