klasik 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +314 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +127 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +7 -0
- package/dist/k8s-client-generator.d.ts +52 -0
- package/dist/k8s-client-generator.js +119 -0
- package/dist/spec-downloader.d.ts +53 -0
- package/dist/spec-downloader.js +213 -0
- package/example.md +139 -0
- package/jest.config.js +10 -0
- package/package.json +39 -0
- package/src/cli.ts +103 -0
- package/src/index.ts +2 -0
- package/src/k8s-client-generator.ts +145 -0
- package/src/spec-downloader.ts +233 -0
- package/test/k8s-client-generator.test.ts +257 -0
- package/tsconfig.json +20 -0
package/README.md
ADDED
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
# klasik
|
|
2
|
+
|
|
3
|
+
Download OpenAPI specifications from remote URLs and generate TypeScript clients with class-transformer support for Kubernetes and other APIs.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- ๐ฅ **Download OpenAPI specs** from remote URLs or local files
|
|
8
|
+
- ๐ **Multiple input formats** - HTTP/HTTPS URLs, file:// URLs, absolute/relative paths
|
|
9
|
+
- ๐ **Automatic transformation** - Converts API responses to class instances using class-transformer
|
|
10
|
+
- ๐ฏ **Type-safe** - Full TypeScript support with decorators
|
|
11
|
+
- ๐ ๏ธ **Configurable** - Custom headers, timeouts, and templates
|
|
12
|
+
- ๐งช **Well-tested** - Comprehensive test coverage (11 tests passing)
|
|
13
|
+
- ๐ฆ **Easy to use** - Simple CLI and programmatic API
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install klasik
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Quick Start
|
|
22
|
+
|
|
23
|
+
### CLI Usage
|
|
24
|
+
|
|
25
|
+
Generate a TypeScript client from a remote OpenAPI spec:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npx klasik generate \
|
|
29
|
+
--url https://raw.githubusercontent.com/kubernetes/kubernetes/master/api/openapi-spec/swagger.json \
|
|
30
|
+
--output ./k8s-client
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Generate from a local OpenAPI spec file:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
# Absolute path
|
|
37
|
+
npx klasik generate \
|
|
38
|
+
--url /path/to/openapi.json \
|
|
39
|
+
--output ./client
|
|
40
|
+
|
|
41
|
+
# Relative path
|
|
42
|
+
npx klasik generate \
|
|
43
|
+
--url ./specs/openapi.json \
|
|
44
|
+
--output ./client
|
|
45
|
+
|
|
46
|
+
# file:// URL
|
|
47
|
+
npx klasik generate \
|
|
48
|
+
--url file:///path/to/openapi.json \
|
|
49
|
+
--output ./client
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Download an OpenAPI spec without generating:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
npx klasik download \
|
|
56
|
+
--url https://api.example.com/openapi.json \
|
|
57
|
+
--output ./specs/api-spec.json
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Programmatic Usage
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
import { K8sClientGenerator } from 'klasik';
|
|
64
|
+
|
|
65
|
+
const generator = new K8sClientGenerator();
|
|
66
|
+
|
|
67
|
+
await generator.generate({
|
|
68
|
+
specUrl: 'https://raw.githubusercontent.com/kubernetes/kubernetes/master/api/openapi-spec/swagger.json',
|
|
69
|
+
outputDir: './k8s-client',
|
|
70
|
+
});
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## CLI Commands
|
|
74
|
+
|
|
75
|
+
### `generate`
|
|
76
|
+
|
|
77
|
+
Generate a TypeScript client from an OpenAPI spec (remote URL or local file).
|
|
78
|
+
|
|
79
|
+
**Options:**
|
|
80
|
+
- `-u, --url <url>` - URL or file path to the OpenAPI spec (required)
|
|
81
|
+
- Supports: `https://...`, `http://...`, `file://...`, `/absolute/path`, `./relative/path`
|
|
82
|
+
- `-o, --output <dir>` - Output directory for generated client code (required)
|
|
83
|
+
- `-H, --header <header...>` - Custom headers for HTTP requests (format: "Key: Value")
|
|
84
|
+
- `-t, --template <dir>` - Custom template directory
|
|
85
|
+
- `-k, --keep-spec` - Keep the downloaded spec file after generation
|
|
86
|
+
- `--timeout <ms>` - Request timeout in milliseconds for HTTP requests (default: 30000)
|
|
87
|
+
|
|
88
|
+
**Examples:**
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
# From remote URL
|
|
92
|
+
klasik generate \
|
|
93
|
+
--url https://api.example.com/openapi.json \
|
|
94
|
+
--output ./client \
|
|
95
|
+
--header "Authorization: Bearer token123" \
|
|
96
|
+
--timeout 60000
|
|
97
|
+
|
|
98
|
+
# From local file
|
|
99
|
+
klasik generate \
|
|
100
|
+
--url ./my-spec.json \
|
|
101
|
+
--output ./client
|
|
102
|
+
|
|
103
|
+
# From file:// URL
|
|
104
|
+
klasik generate \
|
|
105
|
+
--url file:///Users/me/specs/api.json \
|
|
106
|
+
--output ./client
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### `download`
|
|
110
|
+
|
|
111
|
+
Download an OpenAPI spec from a remote URL without generating code.
|
|
112
|
+
|
|
113
|
+
**Options:**
|
|
114
|
+
- `-u, --url <url>` - Remote URL to download the OpenAPI spec from (required)
|
|
115
|
+
- `-o, --output <file>` - Output file path for the downloaded spec (required)
|
|
116
|
+
- `-H, --header <header...>` - Custom headers for the request
|
|
117
|
+
- `--timeout <ms>` - Request timeout in milliseconds (default: 30000)
|
|
118
|
+
|
|
119
|
+
**Example:**
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
klasik download \
|
|
123
|
+
--url https://api.example.com/openapi.json \
|
|
124
|
+
--output ./specs/api-spec.json \
|
|
125
|
+
--header "Authorization: Bearer token123"
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Programmatic API
|
|
129
|
+
|
|
130
|
+
### K8sClientGenerator
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
import { K8sClientGenerator } from 'klasik';
|
|
134
|
+
|
|
135
|
+
const generator = new K8sClientGenerator();
|
|
136
|
+
|
|
137
|
+
await generator.generate({
|
|
138
|
+
specUrl: 'https://api.example.com/openapi.json',
|
|
139
|
+
outputDir: './client',
|
|
140
|
+
headers: {
|
|
141
|
+
'Authorization': 'Bearer token123',
|
|
142
|
+
'X-Custom-Header': 'value'
|
|
143
|
+
},
|
|
144
|
+
templateDir: './custom-templates', // Optional
|
|
145
|
+
keepSpec: true, // Keep downloaded spec file
|
|
146
|
+
timeout: 60000 // Request timeout in ms
|
|
147
|
+
});
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### SpecDownloader
|
|
151
|
+
|
|
152
|
+
```typescript
|
|
153
|
+
import { SpecDownloader } from 'klasik';
|
|
154
|
+
|
|
155
|
+
const downloader = new SpecDownloader();
|
|
156
|
+
|
|
157
|
+
const specPath = await downloader.download({
|
|
158
|
+
url: 'https://api.example.com/openapi.json',
|
|
159
|
+
outputPath: './specs/api-spec.json',
|
|
160
|
+
headers: {
|
|
161
|
+
'Authorization': 'Bearer token123'
|
|
162
|
+
},
|
|
163
|
+
timeout: 30000
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
console.log(`Spec downloaded to: ${specPath}`);
|
|
167
|
+
|
|
168
|
+
// Clean up temporary files
|
|
169
|
+
downloader.cleanupTemp();
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## Generated Client Features
|
|
173
|
+
|
|
174
|
+
The generated TypeScript client includes:
|
|
175
|
+
|
|
176
|
+
- โ
**Class-transformer decorators** - `@Expose()` and `@Type()` on all models
|
|
177
|
+
- โ
**Automatic response transformation** - API responses converted to class instances
|
|
178
|
+
- โ
**Runtime type metadata** - Static `attributeTypeMap` on all models
|
|
179
|
+
- โ
**Union type support** - `anyOf` schemas become TypeScript unions
|
|
180
|
+
- โ
**Vendor extensions** - Preserved in JSDoc comments and metadata
|
|
181
|
+
- โ
**Error handling** - Configurable transformation error handlers
|
|
182
|
+
- โ
**Configuration options** - Enable/disable transformation, custom error handlers
|
|
183
|
+
|
|
184
|
+
### Example Generated Model
|
|
185
|
+
|
|
186
|
+
```typescript
|
|
187
|
+
import { Expose, Type } from 'class-transformer';
|
|
188
|
+
|
|
189
|
+
export class User {
|
|
190
|
+
@Expose()
|
|
191
|
+
'id': string;
|
|
192
|
+
|
|
193
|
+
@Expose()
|
|
194
|
+
'name': string;
|
|
195
|
+
|
|
196
|
+
@Expose()
|
|
197
|
+
@Type(() => Profile)
|
|
198
|
+
'profile'?: Profile;
|
|
199
|
+
|
|
200
|
+
static readonly attributeTypeMap = [
|
|
201
|
+
{
|
|
202
|
+
"name": "id",
|
|
203
|
+
"baseName": "id",
|
|
204
|
+
"type": "string",
|
|
205
|
+
"format": "",
|
|
206
|
+
"description": "User ID",
|
|
207
|
+
"vendorExtensions": {}
|
|
208
|
+
},
|
|
209
|
+
// ... more properties
|
|
210
|
+
];
|
|
211
|
+
}
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### Using the Generated Client
|
|
215
|
+
|
|
216
|
+
```typescript
|
|
217
|
+
import { DefaultApi, Configuration } from './generated-client';
|
|
218
|
+
import { plainToInstance } from 'class-transformer';
|
|
219
|
+
|
|
220
|
+
// Create API client
|
|
221
|
+
const config = new Configuration({
|
|
222
|
+
basePath: 'https://api.example.com',
|
|
223
|
+
enableResponseTransformation: true, // Default
|
|
224
|
+
onTransformationError: (error, modelClass, data) => {
|
|
225
|
+
console.error('Transformation failed:', error);
|
|
226
|
+
}
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
const api = new DefaultApi(config);
|
|
230
|
+
|
|
231
|
+
// Get user - response is automatically transformed to User class instance
|
|
232
|
+
const response = await api.getUserById({ id: '123' });
|
|
233
|
+
const user = response.data; // user is instanceof User โ
|
|
234
|
+
|
|
235
|
+
console.log(user.name); // Fully typed!
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
## Advanced Configuration
|
|
239
|
+
|
|
240
|
+
### Custom Error Handling
|
|
241
|
+
|
|
242
|
+
```typescript
|
|
243
|
+
const config = new Configuration({
|
|
244
|
+
basePath: 'https://api.example.com',
|
|
245
|
+
onTransformationError: (error, modelClass, data) => {
|
|
246
|
+
// Log to custom logger
|
|
247
|
+
logger.error('Failed to transform response', {
|
|
248
|
+
error: error.message,
|
|
249
|
+
modelClass: modelClass.name,
|
|
250
|
+
rawData: data
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
// Send to error tracking
|
|
254
|
+
Sentry.captureException(error);
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
### Disable Transformation
|
|
260
|
+
|
|
261
|
+
```typescript
|
|
262
|
+
const config = new Configuration({
|
|
263
|
+
basePath: 'https://api.example.com',
|
|
264
|
+
enableResponseTransformation: false // Get plain objects
|
|
265
|
+
});
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
## Requirements
|
|
269
|
+
|
|
270
|
+
- Node.js >= 16
|
|
271
|
+
- TypeScript >= 5.0 (for experimentalDecorators support)
|
|
272
|
+
|
|
273
|
+
### TypeScript Configuration
|
|
274
|
+
|
|
275
|
+
Your `tsconfig.json` must include:
|
|
276
|
+
|
|
277
|
+
```json
|
|
278
|
+
{
|
|
279
|
+
"compilerOptions": {
|
|
280
|
+
"experimentalDecorators": true,
|
|
281
|
+
"emitDecoratorMetadata": true
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
## Development
|
|
287
|
+
|
|
288
|
+
```bash
|
|
289
|
+
# Install dependencies
|
|
290
|
+
npm install
|
|
291
|
+
|
|
292
|
+
# Build
|
|
293
|
+
npm run build
|
|
294
|
+
|
|
295
|
+
# Run tests
|
|
296
|
+
npm test
|
|
297
|
+
|
|
298
|
+
# Watch mode
|
|
299
|
+
npm run dev
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
## License
|
|
303
|
+
|
|
304
|
+
MIT
|
|
305
|
+
|
|
306
|
+
## Related Projects
|
|
307
|
+
|
|
308
|
+
- [openapi-class-transformer](https://github.com/example/openapi-class-transformer) - The underlying generator used by this package
|
|
309
|
+
- [class-transformer](https://github.com/typestack/class-transformer) - Transformation library
|
|
310
|
+
- [OpenAPI Generator](https://github.com/OpenAPITools/openapi-generator) - OpenAPI code generator
|
|
311
|
+
|
|
312
|
+
## Contributing
|
|
313
|
+
|
|
314
|
+
Contributions are welcome! Please open an issue or submit a pull request.
|
package/dist/cli.d.ts
ADDED
package/dist/cli.js
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
4
|
+
if (k2 === undefined) k2 = k;
|
|
5
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
6
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
7
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
8
|
+
}
|
|
9
|
+
Object.defineProperty(o, k2, desc);
|
|
10
|
+
}) : (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
o[k2] = m[k];
|
|
13
|
+
}));
|
|
14
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
15
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
16
|
+
}) : function(o, v) {
|
|
17
|
+
o["default"] = v;
|
|
18
|
+
});
|
|
19
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
20
|
+
var ownKeys = function(o) {
|
|
21
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
22
|
+
var ar = [];
|
|
23
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
24
|
+
return ar;
|
|
25
|
+
};
|
|
26
|
+
return ownKeys(o);
|
|
27
|
+
};
|
|
28
|
+
return function (mod) {
|
|
29
|
+
if (mod && mod.__esModule) return mod;
|
|
30
|
+
var result = {};
|
|
31
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
32
|
+
__setModuleDefault(result, mod);
|
|
33
|
+
return result;
|
|
34
|
+
};
|
|
35
|
+
})();
|
|
36
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
37
|
+
const commander_1 = require("commander");
|
|
38
|
+
const k8s_client_generator_1 = require("./k8s-client-generator");
|
|
39
|
+
const path = __importStar(require("path"));
|
|
40
|
+
const program = new commander_1.Command();
|
|
41
|
+
program
|
|
42
|
+
.name('klasik')
|
|
43
|
+
.description('Download OpenAPI specs from remote URLs and generate TypeScript clients with class-transformer support')
|
|
44
|
+
.version('1.0.0');
|
|
45
|
+
program
|
|
46
|
+
.command('generate')
|
|
47
|
+
.description('Generate TypeScript client from a remote OpenAPI spec')
|
|
48
|
+
.requiredOption('-u, --url <url>', 'Remote URL to download the OpenAPI spec from')
|
|
49
|
+
.requiredOption('-o, --output <dir>', 'Output directory for generated client code')
|
|
50
|
+
.option('-m, --mode <mode>', 'Generation mode: "full" (models + APIs + config) or "models-only"', 'full')
|
|
51
|
+
.option('-H, --header <header...>', 'Custom headers for the request (format: "Key: Value")')
|
|
52
|
+
.option('-t, --template <dir>', 'Custom template directory')
|
|
53
|
+
.option('-k, --keep-spec', 'Keep the downloaded spec file after generation', false)
|
|
54
|
+
.option('--timeout <ms>', 'Request timeout in milliseconds', '30000')
|
|
55
|
+
.action(async (options) => {
|
|
56
|
+
try {
|
|
57
|
+
// Validate mode
|
|
58
|
+
if (options.mode !== 'full' && options.mode !== 'models-only') {
|
|
59
|
+
console.error('Error: --mode must be either "full" or "models-only"');
|
|
60
|
+
process.exit(1);
|
|
61
|
+
}
|
|
62
|
+
// Parse headers if provided
|
|
63
|
+
const headers = {};
|
|
64
|
+
if (options.header) {
|
|
65
|
+
for (const header of options.header) {
|
|
66
|
+
const [key, ...valueParts] = header.split(':');
|
|
67
|
+
const value = valueParts.join(':').trim();
|
|
68
|
+
if (key && value) {
|
|
69
|
+
headers[key.trim()] = value;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// Resolve output directory to absolute path
|
|
74
|
+
const outputDir = path.resolve(options.output);
|
|
75
|
+
const generator = new k8s_client_generator_1.K8sClientGenerator();
|
|
76
|
+
await generator.generate({
|
|
77
|
+
specUrl: options.url,
|
|
78
|
+
outputDir,
|
|
79
|
+
mode: options.mode,
|
|
80
|
+
headers: Object.keys(headers).length > 0 ? headers : undefined,
|
|
81
|
+
templateDir: options.template,
|
|
82
|
+
keepSpec: options.keepSpec,
|
|
83
|
+
timeout: parseInt(options.timeout, 10),
|
|
84
|
+
});
|
|
85
|
+
process.exit(0);
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
console.error('Error:', error instanceof Error ? error.message : error);
|
|
89
|
+
process.exit(1);
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
program
|
|
93
|
+
.command('download')
|
|
94
|
+
.description('Download an OpenAPI spec from a remote URL (without generating)')
|
|
95
|
+
.requiredOption('-u, --url <url>', 'Remote URL to download the OpenAPI spec from')
|
|
96
|
+
.requiredOption('-o, --output <file>', 'Output file path for the downloaded spec')
|
|
97
|
+
.option('-H, --header <header...>', 'Custom headers for the request (format: "Key: Value")')
|
|
98
|
+
.option('--timeout <ms>', 'Request timeout in milliseconds', '30000')
|
|
99
|
+
.action(async (options) => {
|
|
100
|
+
try {
|
|
101
|
+
const { SpecDownloader } = await Promise.resolve().then(() => __importStar(require('./spec-downloader')));
|
|
102
|
+
// Parse headers if provided
|
|
103
|
+
const headers = {};
|
|
104
|
+
if (options.header) {
|
|
105
|
+
for (const header of options.header) {
|
|
106
|
+
const [key, ...valueParts] = header.split(':');
|
|
107
|
+
const value = valueParts.join(':').trim();
|
|
108
|
+
if (key && value) {
|
|
109
|
+
headers[key.trim()] = value;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
const downloader = new SpecDownloader();
|
|
114
|
+
await downloader.download({
|
|
115
|
+
url: options.url,
|
|
116
|
+
outputPath: path.resolve(options.output),
|
|
117
|
+
headers: Object.keys(headers).length > 0 ? headers : undefined,
|
|
118
|
+
timeout: parseInt(options.timeout, 10),
|
|
119
|
+
});
|
|
120
|
+
process.exit(0);
|
|
121
|
+
}
|
|
122
|
+
catch (error) {
|
|
123
|
+
console.error('Error:', error instanceof Error ? error.message : error);
|
|
124
|
+
process.exit(1);
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
program.parse();
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SpecDownloader = exports.K8sClientGenerator = void 0;
|
|
4
|
+
var k8s_client_generator_1 = require("./k8s-client-generator");
|
|
5
|
+
Object.defineProperty(exports, "K8sClientGenerator", { enumerable: true, get: function () { return k8s_client_generator_1.K8sClientGenerator; } });
|
|
6
|
+
var spec_downloader_1 = require("./spec-downloader");
|
|
7
|
+
Object.defineProperty(exports, "SpecDownloader", { enumerable: true, get: function () { return spec_downloader_1.SpecDownloader; } });
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
export type GenerationMode = 'full' | 'models-only';
|
|
2
|
+
export interface K8sClientGeneratorOptions {
|
|
3
|
+
/**
|
|
4
|
+
* Remote URL to download the OpenAPI spec from
|
|
5
|
+
*/
|
|
6
|
+
specUrl: string;
|
|
7
|
+
/**
|
|
8
|
+
* Output directory for generated client code
|
|
9
|
+
*/
|
|
10
|
+
outputDir: string;
|
|
11
|
+
/**
|
|
12
|
+
* Generation mode
|
|
13
|
+
* - 'full': Generate models, APIs, and configuration (default)
|
|
14
|
+
* - 'models-only': Generate only model classes
|
|
15
|
+
* @default 'full'
|
|
16
|
+
*/
|
|
17
|
+
mode?: GenerationMode;
|
|
18
|
+
/**
|
|
19
|
+
* Optional headers to include in the spec download request
|
|
20
|
+
*/
|
|
21
|
+
headers?: Record<string, string>;
|
|
22
|
+
/**
|
|
23
|
+
* Optional custom template directory
|
|
24
|
+
*/
|
|
25
|
+
templateDir?: string;
|
|
26
|
+
/**
|
|
27
|
+
* Whether to keep the downloaded spec file after generation
|
|
28
|
+
* @default false
|
|
29
|
+
*/
|
|
30
|
+
keepSpec?: boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Request timeout for downloading spec in milliseconds
|
|
33
|
+
* @default 30000
|
|
34
|
+
*/
|
|
35
|
+
timeout?: number;
|
|
36
|
+
}
|
|
37
|
+
export declare class K8sClientGenerator {
|
|
38
|
+
private downloader;
|
|
39
|
+
constructor();
|
|
40
|
+
/**
|
|
41
|
+
* Generate TypeScript client from a remote OpenAPI spec URL
|
|
42
|
+
*/
|
|
43
|
+
generate(options: K8sClientGeneratorOptions): Promise<void>;
|
|
44
|
+
/**
|
|
45
|
+
* Prepare the output directory
|
|
46
|
+
*/
|
|
47
|
+
private prepareOutputDirectory;
|
|
48
|
+
/**
|
|
49
|
+
* Clean up the downloaded spec file
|
|
50
|
+
*/
|
|
51
|
+
private cleanupSpecFile;
|
|
52
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.K8sClientGenerator = void 0;
|
|
37
|
+
const openapi_class_transformer_1 = require("openapi-class-transformer");
|
|
38
|
+
const spec_downloader_1 = require("./spec-downloader");
|
|
39
|
+
const fs = __importStar(require("fs"));
|
|
40
|
+
class K8sClientGenerator {
|
|
41
|
+
constructor() {
|
|
42
|
+
this.downloader = new spec_downloader_1.SpecDownloader();
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Generate TypeScript client from a remote OpenAPI spec URL
|
|
46
|
+
*/
|
|
47
|
+
async generate(options) {
|
|
48
|
+
const { specUrl, outputDir, mode = 'full', headers, templateDir, keepSpec = false, timeout, } = options;
|
|
49
|
+
let specPath;
|
|
50
|
+
try {
|
|
51
|
+
// Step 1: Download the OpenAPI spec
|
|
52
|
+
console.log('Step 1: Downloading OpenAPI specification...');
|
|
53
|
+
const downloadOptions = {
|
|
54
|
+
url: specUrl,
|
|
55
|
+
headers,
|
|
56
|
+
timeout,
|
|
57
|
+
};
|
|
58
|
+
specPath = await this.downloader.download(downloadOptions);
|
|
59
|
+
// Step 2: Validate output directory
|
|
60
|
+
console.log('Step 2: Preparing output directory...');
|
|
61
|
+
this.prepareOutputDirectory(outputDir);
|
|
62
|
+
// Step 3: Generate client using openapi-class-transformer
|
|
63
|
+
const modeLabel = mode === 'models-only' ? 'models only' : 'full client';
|
|
64
|
+
console.log(`Step 3: Generating TypeScript ${modeLabel}...`);
|
|
65
|
+
const generatorOptions = {
|
|
66
|
+
inputSpec: specPath,
|
|
67
|
+
outputDir,
|
|
68
|
+
modelsOnly: mode === 'models-only',
|
|
69
|
+
};
|
|
70
|
+
// Only add templateDir if it's provided
|
|
71
|
+
if (templateDir) {
|
|
72
|
+
generatorOptions.templateDir = templateDir;
|
|
73
|
+
}
|
|
74
|
+
const generator = new openapi_class_transformer_1.Generator(generatorOptions);
|
|
75
|
+
await generator.generate();
|
|
76
|
+
console.log('โ
Client generation completed successfully!');
|
|
77
|
+
console.log(`๐ Generated files location: ${outputDir}`);
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
console.error('โ Client generation failed:', error);
|
|
81
|
+
throw error;
|
|
82
|
+
}
|
|
83
|
+
finally {
|
|
84
|
+
// Cleanup
|
|
85
|
+
if (!keepSpec && specPath) {
|
|
86
|
+
this.cleanupSpecFile(specPath);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Prepare the output directory
|
|
92
|
+
*/
|
|
93
|
+
prepareOutputDirectory(outputDir) {
|
|
94
|
+
if (!fs.existsSync(outputDir)) {
|
|
95
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
96
|
+
console.log(`Created output directory: ${outputDir}`);
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
console.log(`Using existing output directory: ${outputDir}`);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Clean up the downloaded spec file
|
|
104
|
+
*/
|
|
105
|
+
cleanupSpecFile(specPath) {
|
|
106
|
+
try {
|
|
107
|
+
if (fs.existsSync(specPath)) {
|
|
108
|
+
fs.unlinkSync(specPath);
|
|
109
|
+
console.log(`Cleaned up downloaded spec file: ${specPath}`);
|
|
110
|
+
}
|
|
111
|
+
// Also cleanup temp directory if empty
|
|
112
|
+
this.downloader.cleanupTemp();
|
|
113
|
+
}
|
|
114
|
+
catch (error) {
|
|
115
|
+
console.warn('Warning: Failed to cleanup spec file:', error);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
exports.K8sClientGenerator = K8sClientGenerator;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
export interface DownloadOptions {
|
|
2
|
+
/**
|
|
3
|
+
* URL or file path to the OpenAPI spec
|
|
4
|
+
* Supports:
|
|
5
|
+
* - HTTP/HTTPS URLs: https://example.com/spec.json
|
|
6
|
+
* - File URLs: file:///path/to/spec.json
|
|
7
|
+
* - Absolute paths: /path/to/spec.json
|
|
8
|
+
* - Relative paths: ./spec.json, ../specs/api.json
|
|
9
|
+
*/
|
|
10
|
+
url: string;
|
|
11
|
+
/**
|
|
12
|
+
* Optional output path to save the downloaded spec
|
|
13
|
+
* If not provided, will save to a temp file (for HTTP) or use the source path (for files)
|
|
14
|
+
*/
|
|
15
|
+
outputPath?: string;
|
|
16
|
+
/**
|
|
17
|
+
* Optional headers to include in the request (only used for HTTP/HTTPS)
|
|
18
|
+
*/
|
|
19
|
+
headers?: Record<string, string>;
|
|
20
|
+
/**
|
|
21
|
+
* Request timeout in milliseconds (only used for HTTP/HTTPS)
|
|
22
|
+
* @default 30000
|
|
23
|
+
*/
|
|
24
|
+
timeout?: number;
|
|
25
|
+
}
|
|
26
|
+
export declare class SpecDownloader {
|
|
27
|
+
/**
|
|
28
|
+
* Download an OpenAPI specification from a URL or load from a local file
|
|
29
|
+
* @param options Download options
|
|
30
|
+
* @returns Path to the spec file
|
|
31
|
+
*/
|
|
32
|
+
download(options: DownloadOptions): Promise<string>;
|
|
33
|
+
/**
|
|
34
|
+
* Check if the URL is a local file path
|
|
35
|
+
*/
|
|
36
|
+
private isLocalFile;
|
|
37
|
+
/**
|
|
38
|
+
* Load and validate an OpenAPI spec from a local file
|
|
39
|
+
*/
|
|
40
|
+
private loadLocalFile;
|
|
41
|
+
/**
|
|
42
|
+
* Generate a temporary file path based on the URL
|
|
43
|
+
*/
|
|
44
|
+
private generateTempPath;
|
|
45
|
+
/**
|
|
46
|
+
* Validate that the downloaded content is an OpenAPI spec
|
|
47
|
+
*/
|
|
48
|
+
private validateSpec;
|
|
49
|
+
/**
|
|
50
|
+
* Clean up temporary files
|
|
51
|
+
*/
|
|
52
|
+
cleanupTemp(): void;
|
|
53
|
+
}
|