ng-openapi 0.0.2 → 0.0.4
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/README.md +52 -32
- package/cli.cjs +265 -16
- package/index.js +260 -13
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Angular OpenAPI client generator
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/ng-openapi)
|
|
4
|
+
## 💪 Made with ❤️ by Angular Devs for Angular Devs
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
## Quick Start Guide
|
|
3
8
|
## Installation
|
|
4
9
|
|
|
5
10
|
```bash
|
|
@@ -84,13 +89,13 @@ ng-openapi -i ./swagger.json -o ./src/api --date-type string
|
|
|
84
89
|
|
|
85
90
|
### Optional Fields
|
|
86
91
|
|
|
87
|
-
- `
|
|
88
|
-
- `
|
|
89
|
-
- `
|
|
90
|
-
- `
|
|
91
|
-
- `
|
|
92
|
-
- `
|
|
93
|
-
- `
|
|
92
|
+
- `dateType` - How to handle date types: `'string'` or `'Date'` (default: `'Date'`)
|
|
93
|
+
- `enumStyle` - Enum generation style: `'enum'` or `'union'` (default: `'enum'`)
|
|
94
|
+
- `generateEnumBasedOnDescription` - Parse enum values from description field (default: `true`)
|
|
95
|
+
- `generateServices` - Generate Angular services (default: `true`)
|
|
96
|
+
- `customHeaders` - Headers to add to all HTTP requests
|
|
97
|
+
- `responseTypeMapping` - Map content types to Angular HttpClient response types
|
|
98
|
+
- `customizeMethodName` - Function to customize generated method names
|
|
94
99
|
- `compilerOptions` - TypeScript compiler options for code generation
|
|
95
100
|
|
|
96
101
|
## Generated Files Structure
|
|
@@ -104,44 +109,60 @@ output/
|
|
|
104
109
|
│ └── *.service.ts # Angular services
|
|
105
110
|
├── tokens/
|
|
106
111
|
│ └── index.ts # Injection tokens
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
112
|
+
├── utils/
|
|
113
|
+
│ ├── date-transformer.ts # Date transformation interceptor
|
|
114
|
+
│ └── file-download.ts # File download helpers
|
|
115
|
+
├── providers.ts # Provider functions for easy setup
|
|
116
|
+
└── index.ts # Main exports
|
|
110
117
|
```
|
|
111
118
|
|
|
112
119
|
## Angular Integration
|
|
113
120
|
|
|
114
|
-
###
|
|
121
|
+
### 🚀 Easy Setup (Recommended)
|
|
122
|
+
|
|
123
|
+
The simplest way to integrate ng-openapi is using the provider function:
|
|
115
124
|
|
|
116
125
|
```typescript
|
|
117
|
-
|
|
126
|
+
// In your app.config.ts
|
|
127
|
+
import { ApplicationConfig } from '@angular/core';
|
|
128
|
+
import { provideNgOpenapi } from './api/providers';
|
|
118
129
|
|
|
119
|
-
// In your app.config.ts or module
|
|
120
130
|
export const appConfig: ApplicationConfig = {
|
|
121
131
|
providers: [
|
|
122
|
-
|
|
132
|
+
// One-line setup with automatic interceptor configuration
|
|
133
|
+
provideNgOpenapi({
|
|
134
|
+
basePath: 'https://api.example.com'
|
|
135
|
+
}),
|
|
123
136
|
// other providers...
|
|
124
137
|
]
|
|
125
138
|
};
|
|
126
139
|
```
|
|
127
140
|
|
|
128
|
-
|
|
141
|
+
That's it! This automatically configures:
|
|
142
|
+
- ✅ BASE_PATH token
|
|
143
|
+
- ✅ Date transformation interceptor (if using Date type)
|
|
129
144
|
|
|
130
|
-
```typescript
|
|
131
|
-
import { DateInterceptor } from './api/utils/date-transformer';
|
|
132
|
-
import { HTTP_INTERCEPTORS } from '@angular/common/http';
|
|
133
145
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
146
|
+
### Advanced Provider Options
|
|
147
|
+
|
|
148
|
+
```typescript
|
|
149
|
+
// Disable date transformation
|
|
150
|
+
provideNgOpenapi({
|
|
151
|
+
basePath: 'https://api.example.com',
|
|
152
|
+
enableDateTransform: false
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
// Async configuration
|
|
156
|
+
provideNgOpenapiAsync({
|
|
157
|
+
basePath: () => import('./config').then(c => c.apiConfig.baseUrl)
|
|
158
|
+
});
|
|
140
159
|
```
|
|
141
160
|
|
|
142
|
-
|
|
161
|
+
## Using Generated Services
|
|
143
162
|
|
|
144
163
|
```typescript
|
|
164
|
+
import { Component, inject } from '@angular/core';
|
|
165
|
+
import { toSignal } from '@angular/core/rxjs-interop';
|
|
145
166
|
import { UserService } from './api/services';
|
|
146
167
|
import { User } from './api/models';
|
|
147
168
|
|
|
@@ -150,19 +171,19 @@ import { User } from './api/models';
|
|
|
150
171
|
template: `...`
|
|
151
172
|
})
|
|
152
173
|
export class UsersComponent {
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
constructor(private userService: UserService) {}
|
|
174
|
+
private readonly userService = inject(UserService);
|
|
175
|
+
readonly users = toSignal(this.userService.getUsers());
|
|
156
176
|
}
|
|
157
177
|
```
|
|
158
178
|
|
|
159
179
|
## File Download Example
|
|
160
180
|
|
|
161
181
|
```typescript
|
|
182
|
+
import { Component, inject } from '@angular/core';
|
|
162
183
|
import { downloadFileOperator } from './api/utils/file-download';
|
|
163
184
|
|
|
164
185
|
export class ReportComponent {
|
|
165
|
-
|
|
186
|
+
private readonly reportService = inject(ReportService);
|
|
166
187
|
|
|
167
188
|
downloadReport() {
|
|
168
189
|
this.reportService.getReport('pdf', { reportId: 123 })
|
|
@@ -181,8 +202,7 @@ Add these scripts to your `package.json`:
|
|
|
181
202
|
```json
|
|
182
203
|
{
|
|
183
204
|
"scripts": {
|
|
184
|
-
"generate:api": "ng-openapi -c openapi.config.ts"
|
|
185
|
-
"generate:api:watch": "nodemon --watch swagger.json --exec npm run generate:api"
|
|
205
|
+
"generate:api": "ng-openapi -c openapi.config.ts"
|
|
186
206
|
}
|
|
187
207
|
}
|
|
188
208
|
```
|
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 path8 = __toESM(require("path"));
|
|
30
30
|
var fs4 = __toESM(require("fs"));
|
|
31
31
|
|
|
32
32
|
// src/lib/core/swagger-parser.ts
|
|
@@ -85,6 +85,14 @@ var SERVICE_GENERATOR_HEADER_COMMENT = /* @__PURE__ */ __name((controllerName) =
|
|
|
85
85
|
* Do not edit this file manually
|
|
86
86
|
*/
|
|
87
87
|
`, "SERVICE_GENERATOR_HEADER_COMMENT");
|
|
88
|
+
var MAIN_INDEX_GENERATOR_HEADER_COMMENT = defaultHeaderComment + `* Entrypoint for the client
|
|
89
|
+
* Do not edit this file manually
|
|
90
|
+
*/
|
|
91
|
+
`;
|
|
92
|
+
var PROVIDER_GENERATOR_HEADER_COMMENT = defaultHeaderComment + `* Generated provider functions for easy setup
|
|
93
|
+
* Do not edit this file manually
|
|
94
|
+
*/
|
|
95
|
+
`;
|
|
88
96
|
|
|
89
97
|
// src/lib/generators/type/type.generator.ts
|
|
90
98
|
var TypeGenerator = class {
|
|
@@ -705,9 +713,53 @@ var DateTransformerGenerator = class {
|
|
|
705
713
|
}
|
|
706
714
|
};
|
|
707
715
|
|
|
716
|
+
// src/lib/generators/utility/main-index.generator.ts
|
|
717
|
+
var path4 = __toESM(require("path"));
|
|
718
|
+
var MainIndexGenerator = class {
|
|
719
|
+
static {
|
|
720
|
+
__name(this, "MainIndexGenerator");
|
|
721
|
+
}
|
|
722
|
+
project;
|
|
723
|
+
config;
|
|
724
|
+
constructor(project, config) {
|
|
725
|
+
this.project = project;
|
|
726
|
+
this.config = config;
|
|
727
|
+
}
|
|
728
|
+
generateMainIndex(outputRoot) {
|
|
729
|
+
const indexPath = path4.join(outputRoot, "index.ts");
|
|
730
|
+
const sourceFile = this.project.createSourceFile(indexPath, "", {
|
|
731
|
+
overwrite: true
|
|
732
|
+
});
|
|
733
|
+
sourceFile.insertText(0, MAIN_INDEX_GENERATOR_HEADER_COMMENT);
|
|
734
|
+
sourceFile.addExportDeclaration({
|
|
735
|
+
moduleSpecifier: "./models"
|
|
736
|
+
});
|
|
737
|
+
sourceFile.addExportDeclaration({
|
|
738
|
+
moduleSpecifier: "./tokens"
|
|
739
|
+
});
|
|
740
|
+
sourceFile.addExportDeclaration({
|
|
741
|
+
moduleSpecifier: "./providers"
|
|
742
|
+
});
|
|
743
|
+
if (this.config.options.generateServices !== false) {
|
|
744
|
+
sourceFile.addExportDeclaration({
|
|
745
|
+
moduleSpecifier: "./services"
|
|
746
|
+
});
|
|
747
|
+
}
|
|
748
|
+
if (this.config.options.dateType === "Date") {
|
|
749
|
+
sourceFile.addExportDeclaration({
|
|
750
|
+
moduleSpecifier: "./utils/date-transformer"
|
|
751
|
+
});
|
|
752
|
+
}
|
|
753
|
+
sourceFile.addExportDeclaration({
|
|
754
|
+
moduleSpecifier: "./utils/file-download"
|
|
755
|
+
});
|
|
756
|
+
sourceFile.saveSync();
|
|
757
|
+
}
|
|
758
|
+
};
|
|
759
|
+
|
|
708
760
|
// src/lib/generators/service/service.generator.ts
|
|
709
761
|
var import_ts_morph3 = require("ts-morph");
|
|
710
|
-
var
|
|
762
|
+
var path5 = __toESM(require("path"));
|
|
711
763
|
|
|
712
764
|
// src/lib/utils/string.utils.ts
|
|
713
765
|
function camelCase(str) {
|
|
@@ -1434,7 +1486,7 @@ var ServiceGenerator = class {
|
|
|
1434
1486
|
this.methodGenerator = new ServiceMethodGenerator(config);
|
|
1435
1487
|
}
|
|
1436
1488
|
generate(outputRoot) {
|
|
1437
|
-
const outputDir =
|
|
1489
|
+
const outputDir = path5.join(outputRoot, "services");
|
|
1438
1490
|
const paths = this.extractPaths();
|
|
1439
1491
|
const controllerGroups = this.groupPathsByController(paths);
|
|
1440
1492
|
Object.entries(controllerGroups).forEach(([controllerName, operations]) => {
|
|
@@ -1444,7 +1496,7 @@ var ServiceGenerator = class {
|
|
|
1444
1496
|
extractPaths() {
|
|
1445
1497
|
const paths = [];
|
|
1446
1498
|
const swaggerPaths = this.spec.paths || {};
|
|
1447
|
-
Object.entries(swaggerPaths).forEach(([
|
|
1499
|
+
Object.entries(swaggerPaths).forEach(([path9, pathItem]) => {
|
|
1448
1500
|
const methods = [
|
|
1449
1501
|
"get",
|
|
1450
1502
|
"post",
|
|
@@ -1458,7 +1510,7 @@ var ServiceGenerator = class {
|
|
|
1458
1510
|
if (pathItem[method]) {
|
|
1459
1511
|
const operation = pathItem[method];
|
|
1460
1512
|
paths.push({
|
|
1461
|
-
path:
|
|
1513
|
+
path: path9,
|
|
1462
1514
|
method: method.toUpperCase(),
|
|
1463
1515
|
operationId: operation.operationId,
|
|
1464
1516
|
summary: operation.summary,
|
|
@@ -1490,12 +1542,12 @@ var ServiceGenerator = class {
|
|
|
1490
1542
|
}
|
|
1491
1543
|
groupPathsByController(paths) {
|
|
1492
1544
|
const groups = {};
|
|
1493
|
-
paths.forEach((
|
|
1545
|
+
paths.forEach((path9) => {
|
|
1494
1546
|
let controllerName = "Default";
|
|
1495
|
-
if (
|
|
1496
|
-
controllerName =
|
|
1547
|
+
if (path9.tags && path9.tags.length > 0) {
|
|
1548
|
+
controllerName = path9.tags[0];
|
|
1497
1549
|
} else {
|
|
1498
|
-
const pathParts =
|
|
1550
|
+
const pathParts = path9.path.split("/").filter((p) => p && !p.startsWith("{"));
|
|
1499
1551
|
if (pathParts.length > 1) {
|
|
1500
1552
|
controllerName = pascalCase(pathParts[1]);
|
|
1501
1553
|
}
|
|
@@ -1504,13 +1556,13 @@ var ServiceGenerator = class {
|
|
|
1504
1556
|
if (!groups[controllerName]) {
|
|
1505
1557
|
groups[controllerName] = [];
|
|
1506
1558
|
}
|
|
1507
|
-
groups[controllerName].push(
|
|
1559
|
+
groups[controllerName].push(path9);
|
|
1508
1560
|
});
|
|
1509
1561
|
return groups;
|
|
1510
1562
|
}
|
|
1511
1563
|
generateServiceFile(controllerName, operations, outputDir) {
|
|
1512
1564
|
const fileName = `${kebabCase(controllerName)}.service.ts`;
|
|
1513
|
-
const filePath =
|
|
1565
|
+
const filePath = path5.join(outputDir, fileName);
|
|
1514
1566
|
const sourceFile = this.project.createSourceFile(filePath, "", {
|
|
1515
1567
|
overwrite: true
|
|
1516
1568
|
});
|
|
@@ -1667,7 +1719,7 @@ var ServiceGenerator = class {
|
|
|
1667
1719
|
|
|
1668
1720
|
// src/lib/generators/service/service-index.generator.ts
|
|
1669
1721
|
var fs2 = __toESM(require("fs"));
|
|
1670
|
-
var
|
|
1722
|
+
var path6 = __toESM(require("path"));
|
|
1671
1723
|
var ServiceIndexGenerator = class {
|
|
1672
1724
|
static {
|
|
1673
1725
|
__name(this, "ServiceIndexGenerator");
|
|
@@ -1677,8 +1729,8 @@ var ServiceIndexGenerator = class {
|
|
|
1677
1729
|
this.project = project;
|
|
1678
1730
|
}
|
|
1679
1731
|
generateIndex(outputRoot) {
|
|
1680
|
-
const servicesDir =
|
|
1681
|
-
const indexPath =
|
|
1732
|
+
const servicesDir = path6.join(outputRoot, "services");
|
|
1733
|
+
const indexPath = path6.join(servicesDir, "index.ts");
|
|
1682
1734
|
const sourceFile = this.project.createSourceFile(indexPath, "", {
|
|
1683
1735
|
overwrite: true
|
|
1684
1736
|
});
|
|
@@ -1697,6 +1749,198 @@ var ServiceIndexGenerator = class {
|
|
|
1697
1749
|
}
|
|
1698
1750
|
};
|
|
1699
1751
|
|
|
1752
|
+
// src/lib/generators/utility/provider.generator.ts
|
|
1753
|
+
var path7 = __toESM(require("path"));
|
|
1754
|
+
var ProviderGenerator = class {
|
|
1755
|
+
static {
|
|
1756
|
+
__name(this, "ProviderGenerator");
|
|
1757
|
+
}
|
|
1758
|
+
project;
|
|
1759
|
+
config;
|
|
1760
|
+
constructor(project, config) {
|
|
1761
|
+
this.project = project;
|
|
1762
|
+
this.config = config;
|
|
1763
|
+
}
|
|
1764
|
+
generate(outputDir) {
|
|
1765
|
+
const filePath = path7.join(outputDir, "providers.ts");
|
|
1766
|
+
const sourceFile = this.project.createSourceFile(filePath, "", {
|
|
1767
|
+
overwrite: true
|
|
1768
|
+
});
|
|
1769
|
+
sourceFile.insertText(0, PROVIDER_GENERATOR_HEADER_COMMENT);
|
|
1770
|
+
sourceFile.addImportDeclarations([
|
|
1771
|
+
{
|
|
1772
|
+
namedImports: [
|
|
1773
|
+
"EnvironmentProviders",
|
|
1774
|
+
"Provider",
|
|
1775
|
+
"makeEnvironmentProviders"
|
|
1776
|
+
],
|
|
1777
|
+
moduleSpecifier: "@angular/core"
|
|
1778
|
+
},
|
|
1779
|
+
{
|
|
1780
|
+
namedImports: [
|
|
1781
|
+
"HTTP_INTERCEPTORS"
|
|
1782
|
+
],
|
|
1783
|
+
moduleSpecifier: "@angular/common/http"
|
|
1784
|
+
},
|
|
1785
|
+
{
|
|
1786
|
+
namedImports: [
|
|
1787
|
+
"BASE_PATH"
|
|
1788
|
+
],
|
|
1789
|
+
moduleSpecifier: "./tokens"
|
|
1790
|
+
}
|
|
1791
|
+
]);
|
|
1792
|
+
if (this.config.options.dateType === "Date") {
|
|
1793
|
+
sourceFile.addImportDeclaration({
|
|
1794
|
+
namedImports: [
|
|
1795
|
+
"DateInterceptor"
|
|
1796
|
+
],
|
|
1797
|
+
moduleSpecifier: "./utils/date-transformer"
|
|
1798
|
+
});
|
|
1799
|
+
}
|
|
1800
|
+
sourceFile.addInterface({
|
|
1801
|
+
name: "NgOpenapiConfig",
|
|
1802
|
+
isExported: true,
|
|
1803
|
+
docs: [
|
|
1804
|
+
"Configuration options for ng-openapi providers"
|
|
1805
|
+
],
|
|
1806
|
+
properties: [
|
|
1807
|
+
{
|
|
1808
|
+
name: "basePath",
|
|
1809
|
+
type: "string",
|
|
1810
|
+
docs: [
|
|
1811
|
+
"Base API URL"
|
|
1812
|
+
]
|
|
1813
|
+
},
|
|
1814
|
+
{
|
|
1815
|
+
name: "enableDateTransform",
|
|
1816
|
+
type: "boolean",
|
|
1817
|
+
hasQuestionToken: true,
|
|
1818
|
+
docs: [
|
|
1819
|
+
"Enable automatic date transformation (default: true)"
|
|
1820
|
+
]
|
|
1821
|
+
}
|
|
1822
|
+
]
|
|
1823
|
+
});
|
|
1824
|
+
this.addMainProviderFunction(sourceFile);
|
|
1825
|
+
this.addAsyncProviderFunction(sourceFile);
|
|
1826
|
+
sourceFile.saveSync();
|
|
1827
|
+
}
|
|
1828
|
+
addMainProviderFunction(sourceFile) {
|
|
1829
|
+
const hasDateInterceptor = this.config.options.dateType === "Date";
|
|
1830
|
+
const functionBody = `
|
|
1831
|
+
const providers: Provider[] = [
|
|
1832
|
+
// Base path token
|
|
1833
|
+
{
|
|
1834
|
+
provide: BASE_PATH,
|
|
1835
|
+
useValue: config.basePath
|
|
1836
|
+
}
|
|
1837
|
+
];
|
|
1838
|
+
|
|
1839
|
+
${hasDateInterceptor ? `// Add date interceptor if enabled (default: true)
|
|
1840
|
+
if (config.enableDateTransform !== false) {
|
|
1841
|
+
providers.push({
|
|
1842
|
+
provide: HTTP_INTERCEPTORS,
|
|
1843
|
+
useClass: DateInterceptor,
|
|
1844
|
+
multi: true
|
|
1845
|
+
});
|
|
1846
|
+
}` : `// Date transformation not available (dateType: 'string' was used in generation)`}
|
|
1847
|
+
|
|
1848
|
+
return makeEnvironmentProviders(providers);`;
|
|
1849
|
+
sourceFile.addFunction({
|
|
1850
|
+
name: "provideNgOpenapi",
|
|
1851
|
+
isExported: true,
|
|
1852
|
+
docs: [
|
|
1853
|
+
"Provides all necessary configuration for ng-openapi generated services",
|
|
1854
|
+
"",
|
|
1855
|
+
"@example",
|
|
1856
|
+
"```typescript",
|
|
1857
|
+
"// In your app.config.ts",
|
|
1858
|
+
"import { provideNgOpenapi } from './api/providers';",
|
|
1859
|
+
"",
|
|
1860
|
+
"export const appConfig: ApplicationConfig = {",
|
|
1861
|
+
" providers: [",
|
|
1862
|
+
" provideNgOpenapi({",
|
|
1863
|
+
" basePath: 'https://api.example.com'",
|
|
1864
|
+
" }),",
|
|
1865
|
+
" // other providers...",
|
|
1866
|
+
" ]",
|
|
1867
|
+
"};",
|
|
1868
|
+
"```"
|
|
1869
|
+
],
|
|
1870
|
+
parameters: [
|
|
1871
|
+
{
|
|
1872
|
+
name: "config",
|
|
1873
|
+
type: "NgOpenapiConfig"
|
|
1874
|
+
}
|
|
1875
|
+
],
|
|
1876
|
+
returnType: "EnvironmentProviders",
|
|
1877
|
+
statements: functionBody
|
|
1878
|
+
});
|
|
1879
|
+
}
|
|
1880
|
+
addAsyncProviderFunction(sourceFile) {
|
|
1881
|
+
const hasDateInterceptor = this.config.options.dateType === "Date";
|
|
1882
|
+
const functionBody = `
|
|
1883
|
+
const providers: Provider[] = [];
|
|
1884
|
+
|
|
1885
|
+
// Handle async base path
|
|
1886
|
+
if (typeof config.basePath === 'string') {
|
|
1887
|
+
providers.push({
|
|
1888
|
+
provide: BASE_PATH,
|
|
1889
|
+
useValue: config.basePath
|
|
1890
|
+
});
|
|
1891
|
+
} else {
|
|
1892
|
+
providers.push({
|
|
1893
|
+
provide: BASE_PATH,
|
|
1894
|
+
useFactory: config.basePath
|
|
1895
|
+
});
|
|
1896
|
+
}
|
|
1897
|
+
|
|
1898
|
+
${hasDateInterceptor ? `// Add date interceptor if enabled (default: true)
|
|
1899
|
+
if (config.enableDateTransform !== false) {
|
|
1900
|
+
providers.push({
|
|
1901
|
+
provide: HTTP_INTERCEPTORS,
|
|
1902
|
+
useClass: DateInterceptor,
|
|
1903
|
+
multi: true
|
|
1904
|
+
});
|
|
1905
|
+
}` : `// Date transformation not available (dateType: 'string' was used in generation)`}
|
|
1906
|
+
|
|
1907
|
+
return makeEnvironmentProviders(providers);`;
|
|
1908
|
+
sourceFile.addFunction({
|
|
1909
|
+
name: "provideNgOpenapiAsync",
|
|
1910
|
+
isExported: true,
|
|
1911
|
+
docs: [
|
|
1912
|
+
"Alternative function for cases where you need to handle async configuration",
|
|
1913
|
+
"",
|
|
1914
|
+
"@example",
|
|
1915
|
+
"```typescript",
|
|
1916
|
+
"// In your app.config.ts",
|
|
1917
|
+
"import { provideNgOpenapiAsync } from './api/providers';",
|
|
1918
|
+
"",
|
|
1919
|
+
"export const appConfig: ApplicationConfig = {",
|
|
1920
|
+
" providers: [",
|
|
1921
|
+
" provideNgOpenapiAsync({",
|
|
1922
|
+
" basePath: () => import('./config').then(c => c.apiConfig.baseUrl)",
|
|
1923
|
+
" }),",
|
|
1924
|
+
" // other providers...",
|
|
1925
|
+
" ]",
|
|
1926
|
+
"};",
|
|
1927
|
+
"```"
|
|
1928
|
+
],
|
|
1929
|
+
parameters: [
|
|
1930
|
+
{
|
|
1931
|
+
name: "config",
|
|
1932
|
+
type: `{
|
|
1933
|
+
basePath: string | (() => Promise<string>);
|
|
1934
|
+
enableDateTransform?: boolean;
|
|
1935
|
+
}`
|
|
1936
|
+
}
|
|
1937
|
+
],
|
|
1938
|
+
returnType: "EnvironmentProviders",
|
|
1939
|
+
statements: functionBody
|
|
1940
|
+
});
|
|
1941
|
+
}
|
|
1942
|
+
};
|
|
1943
|
+
|
|
1700
1944
|
// src/lib/core/generator.ts
|
|
1701
1945
|
var fs3 = __toESM(require("fs"));
|
|
1702
1946
|
async function generateFromConfig(config) {
|
|
@@ -1740,6 +1984,11 @@ async function generateFromConfig(config) {
|
|
|
1740
1984
|
indexGenerator.generateIndex(outputPath);
|
|
1741
1985
|
console.log(`\u2705 Angular services generated`);
|
|
1742
1986
|
}
|
|
1987
|
+
const providerGenerator = new ProviderGenerator(project, config);
|
|
1988
|
+
providerGenerator.generate(outputPath);
|
|
1989
|
+
console.log(`\u2705 Provider functions generated`);
|
|
1990
|
+
const mainIndexGenerator = new MainIndexGenerator(project, config);
|
|
1991
|
+
mainIndexGenerator.generateMainIndex(outputPath);
|
|
1743
1992
|
console.log("\u{1F389} Generation completed successfully at:", outputPath);
|
|
1744
1993
|
} catch (error) {
|
|
1745
1994
|
if (error instanceof Error) {
|
|
@@ -1755,7 +2004,7 @@ __name(generateFromConfig, "generateFromConfig");
|
|
|
1755
2004
|
// src/lib/cli.ts
|
|
1756
2005
|
var program = new import_commander.Command();
|
|
1757
2006
|
async function loadConfigFile(configPath) {
|
|
1758
|
-
const resolvedPath =
|
|
2007
|
+
const resolvedPath = path8.resolve(configPath);
|
|
1759
2008
|
if (!fs4.existsSync(resolvedPath)) {
|
|
1760
2009
|
throw new Error(`Configuration file not found: ${resolvedPath}`);
|
|
1761
2010
|
}
|
|
@@ -1781,7 +2030,7 @@ async function generateFromOptions(options) {
|
|
|
1781
2030
|
const config = await loadConfigFile(options.config);
|
|
1782
2031
|
await generateFromConfig(config);
|
|
1783
2032
|
} else if (options.input) {
|
|
1784
|
-
const inputPath =
|
|
2033
|
+
const inputPath = path8.resolve(options.input);
|
|
1785
2034
|
if (!fs4.existsSync(inputPath)) {
|
|
1786
2035
|
console.error(`Error: Input file not found: ${inputPath}`);
|
|
1787
2036
|
process.exit(1);
|
package/index.js
CHANGED
|
@@ -127,6 +127,14 @@ var SERVICE_GENERATOR_HEADER_COMMENT = /* @__PURE__ */ __name((controllerName) =
|
|
|
127
127
|
* Do not edit this file manually
|
|
128
128
|
*/
|
|
129
129
|
`, "SERVICE_GENERATOR_HEADER_COMMENT");
|
|
130
|
+
var MAIN_INDEX_GENERATOR_HEADER_COMMENT = defaultHeaderComment + `* Entrypoint for the client
|
|
131
|
+
* Do not edit this file manually
|
|
132
|
+
*/
|
|
133
|
+
`;
|
|
134
|
+
var PROVIDER_GENERATOR_HEADER_COMMENT = defaultHeaderComment + `* Generated provider functions for easy setup
|
|
135
|
+
* Do not edit this file manually
|
|
136
|
+
*/
|
|
137
|
+
`;
|
|
130
138
|
|
|
131
139
|
// src/lib/generators/type/type.generator.ts
|
|
132
140
|
var _TypeGenerator = class _TypeGenerator {
|
|
@@ -745,9 +753,52 @@ var _DateTransformerGenerator = class _DateTransformerGenerator {
|
|
|
745
753
|
__name(_DateTransformerGenerator, "DateTransformerGenerator");
|
|
746
754
|
var DateTransformerGenerator = _DateTransformerGenerator;
|
|
747
755
|
|
|
756
|
+
// src/lib/generators/utility/main-index.generator.ts
|
|
757
|
+
var path4 = __toESM(require("path"));
|
|
758
|
+
var _MainIndexGenerator = class _MainIndexGenerator {
|
|
759
|
+
constructor(project, config) {
|
|
760
|
+
__publicField(this, "project");
|
|
761
|
+
__publicField(this, "config");
|
|
762
|
+
this.project = project;
|
|
763
|
+
this.config = config;
|
|
764
|
+
}
|
|
765
|
+
generateMainIndex(outputRoot) {
|
|
766
|
+
const indexPath = path4.join(outputRoot, "index.ts");
|
|
767
|
+
const sourceFile = this.project.createSourceFile(indexPath, "", {
|
|
768
|
+
overwrite: true
|
|
769
|
+
});
|
|
770
|
+
sourceFile.insertText(0, MAIN_INDEX_GENERATOR_HEADER_COMMENT);
|
|
771
|
+
sourceFile.addExportDeclaration({
|
|
772
|
+
moduleSpecifier: "./models"
|
|
773
|
+
});
|
|
774
|
+
sourceFile.addExportDeclaration({
|
|
775
|
+
moduleSpecifier: "./tokens"
|
|
776
|
+
});
|
|
777
|
+
sourceFile.addExportDeclaration({
|
|
778
|
+
moduleSpecifier: "./providers"
|
|
779
|
+
});
|
|
780
|
+
if (this.config.options.generateServices !== false) {
|
|
781
|
+
sourceFile.addExportDeclaration({
|
|
782
|
+
moduleSpecifier: "./services"
|
|
783
|
+
});
|
|
784
|
+
}
|
|
785
|
+
if (this.config.options.dateType === "Date") {
|
|
786
|
+
sourceFile.addExportDeclaration({
|
|
787
|
+
moduleSpecifier: "./utils/date-transformer"
|
|
788
|
+
});
|
|
789
|
+
}
|
|
790
|
+
sourceFile.addExportDeclaration({
|
|
791
|
+
moduleSpecifier: "./utils/file-download"
|
|
792
|
+
});
|
|
793
|
+
sourceFile.saveSync();
|
|
794
|
+
}
|
|
795
|
+
};
|
|
796
|
+
__name(_MainIndexGenerator, "MainIndexGenerator");
|
|
797
|
+
var MainIndexGenerator = _MainIndexGenerator;
|
|
798
|
+
|
|
748
799
|
// src/lib/generators/service/service.generator.ts
|
|
749
800
|
var import_ts_morph3 = require("ts-morph");
|
|
750
|
-
var
|
|
801
|
+
var path5 = __toESM(require("path"));
|
|
751
802
|
|
|
752
803
|
// src/lib/utils/string.utils.ts
|
|
753
804
|
function camelCase(str) {
|
|
@@ -1478,7 +1529,7 @@ var _ServiceGenerator = class _ServiceGenerator {
|
|
|
1478
1529
|
this.methodGenerator = new ServiceMethodGenerator(config);
|
|
1479
1530
|
}
|
|
1480
1531
|
generate(outputRoot) {
|
|
1481
|
-
const outputDir =
|
|
1532
|
+
const outputDir = path5.join(outputRoot, "services");
|
|
1482
1533
|
const paths = this.extractPaths();
|
|
1483
1534
|
const controllerGroups = this.groupPathsByController(paths);
|
|
1484
1535
|
Object.entries(controllerGroups).forEach(([controllerName, operations]) => {
|
|
@@ -1488,7 +1539,7 @@ var _ServiceGenerator = class _ServiceGenerator {
|
|
|
1488
1539
|
extractPaths() {
|
|
1489
1540
|
const paths = [];
|
|
1490
1541
|
const swaggerPaths = this.spec.paths || {};
|
|
1491
|
-
Object.entries(swaggerPaths).forEach(([
|
|
1542
|
+
Object.entries(swaggerPaths).forEach(([path8, pathItem]) => {
|
|
1492
1543
|
const methods = [
|
|
1493
1544
|
"get",
|
|
1494
1545
|
"post",
|
|
@@ -1502,7 +1553,7 @@ var _ServiceGenerator = class _ServiceGenerator {
|
|
|
1502
1553
|
if (pathItem[method]) {
|
|
1503
1554
|
const operation = pathItem[method];
|
|
1504
1555
|
paths.push({
|
|
1505
|
-
path:
|
|
1556
|
+
path: path8,
|
|
1506
1557
|
method: method.toUpperCase(),
|
|
1507
1558
|
operationId: operation.operationId,
|
|
1508
1559
|
summary: operation.summary,
|
|
@@ -1534,12 +1585,12 @@ var _ServiceGenerator = class _ServiceGenerator {
|
|
|
1534
1585
|
}
|
|
1535
1586
|
groupPathsByController(paths) {
|
|
1536
1587
|
const groups = {};
|
|
1537
|
-
paths.forEach((
|
|
1588
|
+
paths.forEach((path8) => {
|
|
1538
1589
|
let controllerName = "Default";
|
|
1539
|
-
if (
|
|
1540
|
-
controllerName =
|
|
1590
|
+
if (path8.tags && path8.tags.length > 0) {
|
|
1591
|
+
controllerName = path8.tags[0];
|
|
1541
1592
|
} else {
|
|
1542
|
-
const pathParts =
|
|
1593
|
+
const pathParts = path8.path.split("/").filter((p) => p && !p.startsWith("{"));
|
|
1543
1594
|
if (pathParts.length > 1) {
|
|
1544
1595
|
controllerName = pascalCase(pathParts[1]);
|
|
1545
1596
|
}
|
|
@@ -1548,13 +1599,13 @@ var _ServiceGenerator = class _ServiceGenerator {
|
|
|
1548
1599
|
if (!groups[controllerName]) {
|
|
1549
1600
|
groups[controllerName] = [];
|
|
1550
1601
|
}
|
|
1551
|
-
groups[controllerName].push(
|
|
1602
|
+
groups[controllerName].push(path8);
|
|
1552
1603
|
});
|
|
1553
1604
|
return groups;
|
|
1554
1605
|
}
|
|
1555
1606
|
generateServiceFile(controllerName, operations, outputDir) {
|
|
1556
1607
|
const fileName = `${kebabCase(controllerName)}.service.ts`;
|
|
1557
|
-
const filePath =
|
|
1608
|
+
const filePath = path5.join(outputDir, fileName);
|
|
1558
1609
|
const sourceFile = this.project.createSourceFile(filePath, "", {
|
|
1559
1610
|
overwrite: true
|
|
1560
1611
|
});
|
|
@@ -1714,15 +1765,15 @@ var ServiceGenerator = _ServiceGenerator;
|
|
|
1714
1765
|
|
|
1715
1766
|
// src/lib/generators/service/service-index.generator.ts
|
|
1716
1767
|
var fs2 = __toESM(require("fs"));
|
|
1717
|
-
var
|
|
1768
|
+
var path6 = __toESM(require("path"));
|
|
1718
1769
|
var _ServiceIndexGenerator = class _ServiceIndexGenerator {
|
|
1719
1770
|
constructor(project) {
|
|
1720
1771
|
__publicField(this, "project");
|
|
1721
1772
|
this.project = project;
|
|
1722
1773
|
}
|
|
1723
1774
|
generateIndex(outputRoot) {
|
|
1724
|
-
const servicesDir =
|
|
1725
|
-
const indexPath =
|
|
1775
|
+
const servicesDir = path6.join(outputRoot, "services");
|
|
1776
|
+
const indexPath = path6.join(servicesDir, "index.ts");
|
|
1726
1777
|
const sourceFile = this.project.createSourceFile(indexPath, "", {
|
|
1727
1778
|
overwrite: true
|
|
1728
1779
|
});
|
|
@@ -1743,6 +1794,197 @@ var _ServiceIndexGenerator = class _ServiceIndexGenerator {
|
|
|
1743
1794
|
__name(_ServiceIndexGenerator, "ServiceIndexGenerator");
|
|
1744
1795
|
var ServiceIndexGenerator = _ServiceIndexGenerator;
|
|
1745
1796
|
|
|
1797
|
+
// src/lib/generators/utility/provider.generator.ts
|
|
1798
|
+
var path7 = __toESM(require("path"));
|
|
1799
|
+
var _ProviderGenerator = class _ProviderGenerator {
|
|
1800
|
+
constructor(project, config) {
|
|
1801
|
+
__publicField(this, "project");
|
|
1802
|
+
__publicField(this, "config");
|
|
1803
|
+
this.project = project;
|
|
1804
|
+
this.config = config;
|
|
1805
|
+
}
|
|
1806
|
+
generate(outputDir) {
|
|
1807
|
+
const filePath = path7.join(outputDir, "providers.ts");
|
|
1808
|
+
const sourceFile = this.project.createSourceFile(filePath, "", {
|
|
1809
|
+
overwrite: true
|
|
1810
|
+
});
|
|
1811
|
+
sourceFile.insertText(0, PROVIDER_GENERATOR_HEADER_COMMENT);
|
|
1812
|
+
sourceFile.addImportDeclarations([
|
|
1813
|
+
{
|
|
1814
|
+
namedImports: [
|
|
1815
|
+
"EnvironmentProviders",
|
|
1816
|
+
"Provider",
|
|
1817
|
+
"makeEnvironmentProviders"
|
|
1818
|
+
],
|
|
1819
|
+
moduleSpecifier: "@angular/core"
|
|
1820
|
+
},
|
|
1821
|
+
{
|
|
1822
|
+
namedImports: [
|
|
1823
|
+
"HTTP_INTERCEPTORS"
|
|
1824
|
+
],
|
|
1825
|
+
moduleSpecifier: "@angular/common/http"
|
|
1826
|
+
},
|
|
1827
|
+
{
|
|
1828
|
+
namedImports: [
|
|
1829
|
+
"BASE_PATH"
|
|
1830
|
+
],
|
|
1831
|
+
moduleSpecifier: "./tokens"
|
|
1832
|
+
}
|
|
1833
|
+
]);
|
|
1834
|
+
if (this.config.options.dateType === "Date") {
|
|
1835
|
+
sourceFile.addImportDeclaration({
|
|
1836
|
+
namedImports: [
|
|
1837
|
+
"DateInterceptor"
|
|
1838
|
+
],
|
|
1839
|
+
moduleSpecifier: "./utils/date-transformer"
|
|
1840
|
+
});
|
|
1841
|
+
}
|
|
1842
|
+
sourceFile.addInterface({
|
|
1843
|
+
name: "NgOpenapiConfig",
|
|
1844
|
+
isExported: true,
|
|
1845
|
+
docs: [
|
|
1846
|
+
"Configuration options for ng-openapi providers"
|
|
1847
|
+
],
|
|
1848
|
+
properties: [
|
|
1849
|
+
{
|
|
1850
|
+
name: "basePath",
|
|
1851
|
+
type: "string",
|
|
1852
|
+
docs: [
|
|
1853
|
+
"Base API URL"
|
|
1854
|
+
]
|
|
1855
|
+
},
|
|
1856
|
+
{
|
|
1857
|
+
name: "enableDateTransform",
|
|
1858
|
+
type: "boolean",
|
|
1859
|
+
hasQuestionToken: true,
|
|
1860
|
+
docs: [
|
|
1861
|
+
"Enable automatic date transformation (default: true)"
|
|
1862
|
+
]
|
|
1863
|
+
}
|
|
1864
|
+
]
|
|
1865
|
+
});
|
|
1866
|
+
this.addMainProviderFunction(sourceFile);
|
|
1867
|
+
this.addAsyncProviderFunction(sourceFile);
|
|
1868
|
+
sourceFile.saveSync();
|
|
1869
|
+
}
|
|
1870
|
+
addMainProviderFunction(sourceFile) {
|
|
1871
|
+
const hasDateInterceptor = this.config.options.dateType === "Date";
|
|
1872
|
+
const functionBody = `
|
|
1873
|
+
const providers: Provider[] = [
|
|
1874
|
+
// Base path token
|
|
1875
|
+
{
|
|
1876
|
+
provide: BASE_PATH,
|
|
1877
|
+
useValue: config.basePath
|
|
1878
|
+
}
|
|
1879
|
+
];
|
|
1880
|
+
|
|
1881
|
+
${hasDateInterceptor ? `// Add date interceptor if enabled (default: true)
|
|
1882
|
+
if (config.enableDateTransform !== false) {
|
|
1883
|
+
providers.push({
|
|
1884
|
+
provide: HTTP_INTERCEPTORS,
|
|
1885
|
+
useClass: DateInterceptor,
|
|
1886
|
+
multi: true
|
|
1887
|
+
});
|
|
1888
|
+
}` : `// Date transformation not available (dateType: 'string' was used in generation)`}
|
|
1889
|
+
|
|
1890
|
+
return makeEnvironmentProviders(providers);`;
|
|
1891
|
+
sourceFile.addFunction({
|
|
1892
|
+
name: "provideNgOpenapi",
|
|
1893
|
+
isExported: true,
|
|
1894
|
+
docs: [
|
|
1895
|
+
"Provides all necessary configuration for ng-openapi generated services",
|
|
1896
|
+
"",
|
|
1897
|
+
"@example",
|
|
1898
|
+
"```typescript",
|
|
1899
|
+
"// In your app.config.ts",
|
|
1900
|
+
"import { provideNgOpenapi } from './api/providers';",
|
|
1901
|
+
"",
|
|
1902
|
+
"export const appConfig: ApplicationConfig = {",
|
|
1903
|
+
" providers: [",
|
|
1904
|
+
" provideNgOpenapi({",
|
|
1905
|
+
" basePath: 'https://api.example.com'",
|
|
1906
|
+
" }),",
|
|
1907
|
+
" // other providers...",
|
|
1908
|
+
" ]",
|
|
1909
|
+
"};",
|
|
1910
|
+
"```"
|
|
1911
|
+
],
|
|
1912
|
+
parameters: [
|
|
1913
|
+
{
|
|
1914
|
+
name: "config",
|
|
1915
|
+
type: "NgOpenapiConfig"
|
|
1916
|
+
}
|
|
1917
|
+
],
|
|
1918
|
+
returnType: "EnvironmentProviders",
|
|
1919
|
+
statements: functionBody
|
|
1920
|
+
});
|
|
1921
|
+
}
|
|
1922
|
+
addAsyncProviderFunction(sourceFile) {
|
|
1923
|
+
const hasDateInterceptor = this.config.options.dateType === "Date";
|
|
1924
|
+
const functionBody = `
|
|
1925
|
+
const providers: Provider[] = [];
|
|
1926
|
+
|
|
1927
|
+
// Handle async base path
|
|
1928
|
+
if (typeof config.basePath === 'string') {
|
|
1929
|
+
providers.push({
|
|
1930
|
+
provide: BASE_PATH,
|
|
1931
|
+
useValue: config.basePath
|
|
1932
|
+
});
|
|
1933
|
+
} else {
|
|
1934
|
+
providers.push({
|
|
1935
|
+
provide: BASE_PATH,
|
|
1936
|
+
useFactory: config.basePath
|
|
1937
|
+
});
|
|
1938
|
+
}
|
|
1939
|
+
|
|
1940
|
+
${hasDateInterceptor ? `// Add date interceptor if enabled (default: true)
|
|
1941
|
+
if (config.enableDateTransform !== false) {
|
|
1942
|
+
providers.push({
|
|
1943
|
+
provide: HTTP_INTERCEPTORS,
|
|
1944
|
+
useClass: DateInterceptor,
|
|
1945
|
+
multi: true
|
|
1946
|
+
});
|
|
1947
|
+
}` : `// Date transformation not available (dateType: 'string' was used in generation)`}
|
|
1948
|
+
|
|
1949
|
+
return makeEnvironmentProviders(providers);`;
|
|
1950
|
+
sourceFile.addFunction({
|
|
1951
|
+
name: "provideNgOpenapiAsync",
|
|
1952
|
+
isExported: true,
|
|
1953
|
+
docs: [
|
|
1954
|
+
"Alternative function for cases where you need to handle async configuration",
|
|
1955
|
+
"",
|
|
1956
|
+
"@example",
|
|
1957
|
+
"```typescript",
|
|
1958
|
+
"// In your app.config.ts",
|
|
1959
|
+
"import { provideNgOpenapiAsync } from './api/providers';",
|
|
1960
|
+
"",
|
|
1961
|
+
"export const appConfig: ApplicationConfig = {",
|
|
1962
|
+
" providers: [",
|
|
1963
|
+
" provideNgOpenapiAsync({",
|
|
1964
|
+
" basePath: () => import('./config').then(c => c.apiConfig.baseUrl)",
|
|
1965
|
+
" }),",
|
|
1966
|
+
" // other providers...",
|
|
1967
|
+
" ]",
|
|
1968
|
+
"};",
|
|
1969
|
+
"```"
|
|
1970
|
+
],
|
|
1971
|
+
parameters: [
|
|
1972
|
+
{
|
|
1973
|
+
name: "config",
|
|
1974
|
+
type: `{
|
|
1975
|
+
basePath: string | (() => Promise<string>);
|
|
1976
|
+
enableDateTransform?: boolean;
|
|
1977
|
+
}`
|
|
1978
|
+
}
|
|
1979
|
+
],
|
|
1980
|
+
returnType: "EnvironmentProviders",
|
|
1981
|
+
statements: functionBody
|
|
1982
|
+
});
|
|
1983
|
+
}
|
|
1984
|
+
};
|
|
1985
|
+
__name(_ProviderGenerator, "ProviderGenerator");
|
|
1986
|
+
var ProviderGenerator = _ProviderGenerator;
|
|
1987
|
+
|
|
1746
1988
|
// src/lib/core/generator.ts
|
|
1747
1989
|
var fs3 = __toESM(require("fs"));
|
|
1748
1990
|
function generateFromConfig(config) {
|
|
@@ -1787,6 +2029,11 @@ function generateFromConfig(config) {
|
|
|
1787
2029
|
indexGenerator.generateIndex(outputPath);
|
|
1788
2030
|
console.log(`\u2705 Angular services generated`);
|
|
1789
2031
|
}
|
|
2032
|
+
const providerGenerator = new ProviderGenerator(project, config);
|
|
2033
|
+
providerGenerator.generate(outputPath);
|
|
2034
|
+
console.log(`\u2705 Provider functions generated`);
|
|
2035
|
+
const mainIndexGenerator = new MainIndexGenerator(project, config);
|
|
2036
|
+
mainIndexGenerator.generateMainIndex(outputPath);
|
|
1790
2037
|
console.log("\u{1F389} Generation completed successfully at:", outputPath);
|
|
1791
2038
|
} catch (error) {
|
|
1792
2039
|
if (error instanceof Error) {
|