openapi-class-transformer 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/LICENSE +21 -0
- package/README.md +385 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +79 -0
- package/dist/cli.js.map +1 -0
- package/dist/generator.d.ts +41 -0
- package/dist/generator.d.ts.map +1 -0
- package/dist/generator.js +161 -0
- package/dist/generator.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/post-processor.d.ts +72 -0
- package/dist/post-processor.d.ts.map +1 -0
- package/dist/post-processor.js +419 -0
- package/dist/post-processor.js.map +1 -0
- package/package.json +59 -0
- package/templates/apiInner.mustache +506 -0
- package/templates/configuration.mustache +144 -0
- package/templates/modelGeneric.mustache +79 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
# openapi-class-transformer
|
|
2
|
+
|
|
3
|
+
Generate class-transformer compatible TypeScript classes from OpenAPI specifications with full decorator support.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
✨ **Class-Transformer Compatible**: Generates TypeScript classes with `@Expose()` and `@Type()` decorators
|
|
8
|
+
🎯 **Type-Safe**: Full TypeScript support with proper type definitions
|
|
9
|
+
📦 **Vendor Extensions**: Automatically includes all `x-*` properties in JSDoc comments
|
|
10
|
+
🔧 **Customizable**: Support for custom templates and additional properties
|
|
11
|
+
⚡ **Easy to Use**: Simple CLI and programmatic API
|
|
12
|
+
🧪 **Well-Tested**: Comprehensive test coverage
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install openapi-class-transformer
|
|
18
|
+
# or
|
|
19
|
+
yarn add openapi-class-transformer
|
|
20
|
+
# or
|
|
21
|
+
pnpm add openapi-class-transformer
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Usage
|
|
25
|
+
|
|
26
|
+
### CLI
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
# Generate from OpenAPI spec
|
|
30
|
+
npx openapi-class-transformer generate \
|
|
31
|
+
--input ./api-spec.json \
|
|
32
|
+
--output ./src/generated
|
|
33
|
+
|
|
34
|
+
# With custom template directory
|
|
35
|
+
npx openapi-class-transformer generate \
|
|
36
|
+
-i ./api-spec.yaml \
|
|
37
|
+
-o ./src/api \
|
|
38
|
+
-t ./custom-templates
|
|
39
|
+
|
|
40
|
+
# With additional properties
|
|
41
|
+
npx openapi-class-transformer generate \
|
|
42
|
+
-i ./spec.json \
|
|
43
|
+
-o ./output \
|
|
44
|
+
--additional-properties modelPackage=dto,apiPackage=services
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Programmatic API
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
import { Generator } from 'openapi-class-transformer';
|
|
51
|
+
|
|
52
|
+
const generator = new Generator({
|
|
53
|
+
inputSpec: './api-spec.json',
|
|
54
|
+
outputDir: './src/generated',
|
|
55
|
+
// Optional: custom template directory
|
|
56
|
+
templateDir: './custom-templates',
|
|
57
|
+
// Optional: additional OpenAPI Generator properties
|
|
58
|
+
additionalProperties: {
|
|
59
|
+
modelPackage: 'dto',
|
|
60
|
+
apiPackage: 'services'
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
await generator.generate();
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Generated Output
|
|
68
|
+
|
|
69
|
+
Given this OpenAPI schema:
|
|
70
|
+
|
|
71
|
+
```yaml
|
|
72
|
+
components:
|
|
73
|
+
schemas:
|
|
74
|
+
User:
|
|
75
|
+
type: object
|
|
76
|
+
required:
|
|
77
|
+
- id
|
|
78
|
+
- name
|
|
79
|
+
properties:
|
|
80
|
+
id:
|
|
81
|
+
type: string
|
|
82
|
+
name:
|
|
83
|
+
type: string
|
|
84
|
+
profile:
|
|
85
|
+
$ref: '#/components/schemas/Profile'
|
|
86
|
+
Profile:
|
|
87
|
+
type: object
|
|
88
|
+
properties:
|
|
89
|
+
bio:
|
|
90
|
+
type: string
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
The generator creates:
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
import { Expose, Type } from 'class-transformer';
|
|
97
|
+
import { Profile } from './profile.js';
|
|
98
|
+
|
|
99
|
+
export class User {
|
|
100
|
+
/**
|
|
101
|
+
* id
|
|
102
|
+
*/
|
|
103
|
+
@Expose()
|
|
104
|
+
'id': string;
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* name
|
|
108
|
+
*/
|
|
109
|
+
@Expose()
|
|
110
|
+
'name': string;
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* profile
|
|
114
|
+
*/
|
|
115
|
+
@Expose()
|
|
116
|
+
@Type(() => Profile)
|
|
117
|
+
'profile'?: Profile;
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Vendor Extensions
|
|
122
|
+
|
|
123
|
+
All OpenAPI vendor extensions (`x-*` properties) are automatically included in JSDoc comments:
|
|
124
|
+
|
|
125
|
+
```yaml
|
|
126
|
+
properties:
|
|
127
|
+
count:
|
|
128
|
+
anyOf:
|
|
129
|
+
- type: integer
|
|
130
|
+
- type: string
|
|
131
|
+
x-kubernetes-int-or-string: true
|
|
132
|
+
x-custom-property: "custom-value"
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Generates:
|
|
136
|
+
|
|
137
|
+
```typescript
|
|
138
|
+
/**
|
|
139
|
+
* count
|
|
140
|
+
* @x-kubernetes-int-or-string true
|
|
141
|
+
* @x-custom-property "custom-value"
|
|
142
|
+
*/
|
|
143
|
+
@Expose()
|
|
144
|
+
'count': string | number;
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## Use with class-transformer
|
|
148
|
+
|
|
149
|
+
The generated classes work seamlessly with `class-transformer`:
|
|
150
|
+
|
|
151
|
+
```typescript
|
|
152
|
+
import { plainToInstance } from 'class-transformer';
|
|
153
|
+
import { User } from './generated/models/user';
|
|
154
|
+
|
|
155
|
+
const plainData = {
|
|
156
|
+
id: '123',
|
|
157
|
+
name: 'John Doe',
|
|
158
|
+
profile: {
|
|
159
|
+
bio: 'Software developer'
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
const user = plainToInstance(User, plainData);
|
|
164
|
+
// ✅ user is properly typed User instance
|
|
165
|
+
// ✅ user.profile is properly typed Profile instance
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### TypeScript Configuration
|
|
169
|
+
|
|
170
|
+
Ensure your `tsconfig.json` has the following settings to use the generated classes:
|
|
171
|
+
|
|
172
|
+
```json
|
|
173
|
+
{
|
|
174
|
+
"compilerOptions": {
|
|
175
|
+
"experimentalDecorators": true,
|
|
176
|
+
"emitDecoratorMetadata": true,
|
|
177
|
+
"moduleResolution": "node",
|
|
178
|
+
"esModuleInterop": true
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### Dependencies
|
|
184
|
+
|
|
185
|
+
Install `class-transformer` in your project:
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
npm install class-transformer reflect-metadata
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
And import `reflect-metadata` at the top of your entry file:
|
|
192
|
+
|
|
193
|
+
```typescript
|
|
194
|
+
import 'reflect-metadata';
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
## Runtime Type Metadata
|
|
198
|
+
|
|
199
|
+
Each generated class includes a static `attributeTypeMap` property that provides runtime access to property metadata:
|
|
200
|
+
|
|
201
|
+
```typescript
|
|
202
|
+
import { User } from './generated/models/user';
|
|
203
|
+
|
|
204
|
+
// Access type metadata at runtime
|
|
205
|
+
console.log(User.attributeTypeMap);
|
|
206
|
+
/*
|
|
207
|
+
[
|
|
208
|
+
{
|
|
209
|
+
"name": "id",
|
|
210
|
+
"baseName": "id",
|
|
211
|
+
"type": "string",
|
|
212
|
+
"format": ""
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
"name": "name",
|
|
216
|
+
"baseName": "name",
|
|
217
|
+
"type": "string",
|
|
218
|
+
"format": ""
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
"name": "email",
|
|
222
|
+
"baseName": "email",
|
|
223
|
+
"type": "string",
|
|
224
|
+
"format": "email"
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
"name": "profile",
|
|
228
|
+
"baseName": "profile",
|
|
229
|
+
"type": "Profile",
|
|
230
|
+
"format": ""
|
|
231
|
+
}
|
|
232
|
+
]
|
|
233
|
+
*/
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
This is useful for:
|
|
237
|
+
- **Runtime validation** - Check types dynamically
|
|
238
|
+
- **Form generation** - Build UI forms from metadata
|
|
239
|
+
- **Documentation** - Generate API docs from types
|
|
240
|
+
- **Serialization** - Custom serialization logic based on types
|
|
241
|
+
|
|
242
|
+
### Array Types
|
|
243
|
+
|
|
244
|
+
Arrays are represented with the `Array<Type>` notation:
|
|
245
|
+
|
|
246
|
+
```typescript
|
|
247
|
+
console.log(UserList.attributeTypeMap);
|
|
248
|
+
/*
|
|
249
|
+
[
|
|
250
|
+
{
|
|
251
|
+
"name": "users",
|
|
252
|
+
"baseName": "users",
|
|
253
|
+
"type": "Array<User>",
|
|
254
|
+
"format": ""
|
|
255
|
+
}
|
|
256
|
+
]
|
|
257
|
+
*/
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
## Configuration Options
|
|
261
|
+
|
|
262
|
+
### GeneratorOptions
|
|
263
|
+
|
|
264
|
+
```typescript
|
|
265
|
+
interface GeneratorOptions {
|
|
266
|
+
/**
|
|
267
|
+
* Path to the OpenAPI specification file (JSON or YAML)
|
|
268
|
+
*/
|
|
269
|
+
inputSpec: string;
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Output directory for generated files
|
|
273
|
+
*/
|
|
274
|
+
outputDir: string;
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Custom template directory (optional)
|
|
278
|
+
* If not provided, uses bundled templates
|
|
279
|
+
*/
|
|
280
|
+
templateDir?: string;
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Additional OpenAPI Generator properties
|
|
284
|
+
*/
|
|
285
|
+
additionalProperties?: Record<string, string>;
|
|
286
|
+
}
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
### Default Additional Properties
|
|
290
|
+
|
|
291
|
+
The generator uses these defaults (can be overridden):
|
|
292
|
+
|
|
293
|
+
- `withSeparateModelsAndApi`: `true`
|
|
294
|
+
- `modelPackage`: `models`
|
|
295
|
+
- `apiPackage`: `api`
|
|
296
|
+
- `generateAliasAsModel`: `true`
|
|
297
|
+
- `supportsES6`: `true`
|
|
298
|
+
- `useSingleRequestParameter`: `true`
|
|
299
|
+
- `withNodeImports`: `true`
|
|
300
|
+
|
|
301
|
+
## Custom Templates
|
|
302
|
+
|
|
303
|
+
You can provide custom Mustache templates to customize the generated output:
|
|
304
|
+
|
|
305
|
+
1. Copy the default template from `templates/modelGeneric.mustache`
|
|
306
|
+
2. Modify it according to your needs
|
|
307
|
+
3. Pass the template directory to the generator:
|
|
308
|
+
|
|
309
|
+
```typescript
|
|
310
|
+
const generator = new Generator({
|
|
311
|
+
inputSpec: './spec.json',
|
|
312
|
+
outputDir: './output',
|
|
313
|
+
templateDir: './my-templates'
|
|
314
|
+
});
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
## Development
|
|
318
|
+
|
|
319
|
+
```bash
|
|
320
|
+
# Install dependencies
|
|
321
|
+
npm install
|
|
322
|
+
|
|
323
|
+
# Run tests
|
|
324
|
+
npm test
|
|
325
|
+
|
|
326
|
+
# Run tests in watch mode
|
|
327
|
+
npm run test:watch
|
|
328
|
+
|
|
329
|
+
# Build
|
|
330
|
+
npm run build
|
|
331
|
+
|
|
332
|
+
# Run tests with coverage
|
|
333
|
+
npm run test:coverage
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
## Testing
|
|
337
|
+
|
|
338
|
+
The package includes comprehensive test coverage using Jest:
|
|
339
|
+
|
|
340
|
+
```bash
|
|
341
|
+
npm test
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
Tests follow TDD (Test-Driven Development) principles with fixtures in the `test-fixtures` directory.
|
|
345
|
+
|
|
346
|
+
### Test Results
|
|
347
|
+
|
|
348
|
+
Each test generates its output into a separate directory under `test-results/` (gitignored). This allows you to:
|
|
349
|
+
|
|
350
|
+
- **Inspect generated code** manually after running tests
|
|
351
|
+
- **Debug issues** by examining actual output
|
|
352
|
+
- **See examples** of what the generator produces
|
|
353
|
+
|
|
354
|
+
For example, after running tests:
|
|
355
|
+
|
|
356
|
+
```bash
|
|
357
|
+
# View generated User class with @Expose decorators
|
|
358
|
+
cat test-results/expose-decorators/models/user.ts
|
|
359
|
+
|
|
360
|
+
# View generated Replica class with vendor extensions
|
|
361
|
+
cat test-results/vendor-extensions/models/replica.ts
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
Test result directories persist between runs and are organized by test name:
|
|
365
|
+
- `basic-generation/` - Basic class generation
|
|
366
|
+
- `expose-decorators/` - @Expose() decorator tests
|
|
367
|
+
- `type-decorators/` - @Type() decorator tests
|
|
368
|
+
- `import-type-fix/` - Import type conversion tests
|
|
369
|
+
- `vendor-extensions/` - Vendor extension tests
|
|
370
|
+
|
|
371
|
+
See [test-results/README.md](test-results/README.md) for more details.
|
|
372
|
+
|
|
373
|
+
## License
|
|
374
|
+
|
|
375
|
+
MIT
|
|
376
|
+
|
|
377
|
+
## Contributing
|
|
378
|
+
|
|
379
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
380
|
+
|
|
381
|
+
## Credits
|
|
382
|
+
|
|
383
|
+
Built on top of:
|
|
384
|
+
- [OpenAPI Generator](https://openapi-generator.tech/)
|
|
385
|
+
- [class-transformer](https://github.com/typestack/class-transformer)
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
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 generator_1 = require("./generator");
|
|
39
|
+
const path = __importStar(require("path"));
|
|
40
|
+
const program = new commander_1.Command();
|
|
41
|
+
program
|
|
42
|
+
.name('openapi-class-transformer')
|
|
43
|
+
.description('Generate class-transformer compatible TypeScript classes from OpenAPI specs')
|
|
44
|
+
.version('1.0.0');
|
|
45
|
+
program
|
|
46
|
+
.command('generate')
|
|
47
|
+
.description('Generate TypeScript classes from OpenAPI specification')
|
|
48
|
+
.requiredOption('-i, --input <path>', 'Path to OpenAPI specification file')
|
|
49
|
+
.requiredOption('-o, --output <path>', 'Output directory for generated files')
|
|
50
|
+
.option('-t, --template <path>', 'Custom template directory')
|
|
51
|
+
.option('--additional-properties <props>', 'Additional OpenAPI Generator properties (key=value,key2=value2)')
|
|
52
|
+
.action(async (options) => {
|
|
53
|
+
try {
|
|
54
|
+
const additionalProperties = {};
|
|
55
|
+
if (options.additionalProperties) {
|
|
56
|
+
options.additionalProperties.split(',').forEach((prop) => {
|
|
57
|
+
const [key, value] = prop.split('=');
|
|
58
|
+
if (key && value) {
|
|
59
|
+
additionalProperties[key] = value;
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
const generator = new generator_1.Generator({
|
|
64
|
+
inputSpec: path.resolve(options.input),
|
|
65
|
+
outputDir: path.resolve(options.output),
|
|
66
|
+
templateDir: options.template ? path.resolve(options.template) : undefined,
|
|
67
|
+
additionalProperties
|
|
68
|
+
});
|
|
69
|
+
await generator.generate();
|
|
70
|
+
console.log('✅ Generation completed successfully!');
|
|
71
|
+
process.exit(0);
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
console.error('❌ Generation failed:', error instanceof Error ? error.message : error);
|
|
75
|
+
process.exit(1);
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
program.parse(process.argv);
|
|
79
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEA,yCAAoC;AACpC,2CAAwC;AACxC,2CAA6B;AAE7B,MAAM,OAAO,GAAG,IAAI,mBAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,2BAA2B,CAAC;KACjC,WAAW,CAAC,6EAA6E,CAAC;KAC1F,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,OAAO;KACJ,OAAO,CAAC,UAAU,CAAC;KACnB,WAAW,CAAC,wDAAwD,CAAC;KACrE,cAAc,CAAC,oBAAoB,EAAE,oCAAoC,CAAC;KAC1E,cAAc,CAAC,qBAAqB,EAAE,sCAAsC,CAAC;KAC7E,MAAM,CAAC,uBAAuB,EAAE,2BAA2B,CAAC;KAC5D,MAAM,CAAC,iCAAiC,EAAE,iEAAiE,CAAC;KAC5G,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;IACxB,IAAI,CAAC;QACH,MAAM,oBAAoB,GAA2B,EAAE,CAAC;QACxD,IAAI,OAAO,CAAC,oBAAoB,EAAE,CAAC;YACjC,OAAO,CAAC,oBAAoB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,IAAY,EAAE,EAAE;gBAC/D,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;gBACrC,IAAI,GAAG,IAAI,KAAK,EAAE,CAAC;oBACjB,oBAAoB,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;gBACpC,CAAC;YACH,CAAC,CAAC,CAAC;QACL,CAAC;QAED,MAAM,SAAS,GAAG,IAAI,qBAAS,CAAC;YAC9B,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC;YACtC,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC;YACvC,WAAW,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,SAAS;YAC1E,oBAAoB;SACrB,CAAC,CAAC;QAEH,MAAM,SAAS,CAAC,QAAQ,EAAE,CAAC;QAC3B,OAAO,CAAC,GAAG,CAAC,sCAAsC,CAAC,CAAC;QACpD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,sBAAsB,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QACtF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC;AAEL,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export interface GeneratorOptions {
|
|
2
|
+
/**
|
|
3
|
+
* Path to the OpenAPI specification file (JSON or YAML)
|
|
4
|
+
*/
|
|
5
|
+
inputSpec: string;
|
|
6
|
+
/**
|
|
7
|
+
* Output directory for generated files
|
|
8
|
+
*/
|
|
9
|
+
outputDir: string;
|
|
10
|
+
/**
|
|
11
|
+
* Custom template directory (optional)
|
|
12
|
+
* If not provided, uses bundled templates
|
|
13
|
+
*/
|
|
14
|
+
templateDir?: string;
|
|
15
|
+
/**
|
|
16
|
+
* Generate only model classes (skip APIs and configuration)
|
|
17
|
+
* @default false
|
|
18
|
+
*/
|
|
19
|
+
modelsOnly?: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Additional OpenAPI Generator properties
|
|
22
|
+
*/
|
|
23
|
+
additionalProperties?: Record<string, string>;
|
|
24
|
+
}
|
|
25
|
+
export declare class Generator {
|
|
26
|
+
private options;
|
|
27
|
+
constructor(options: GeneratorOptions);
|
|
28
|
+
/**
|
|
29
|
+
* Get the default template directory (bundled with the package)
|
|
30
|
+
*/
|
|
31
|
+
private getDefaultTemplateDir;
|
|
32
|
+
/**
|
|
33
|
+
* Validate generator options
|
|
34
|
+
*/
|
|
35
|
+
private validateOptions;
|
|
36
|
+
/**
|
|
37
|
+
* Generate TypeScript classes from OpenAPI specification
|
|
38
|
+
*/
|
|
39
|
+
generate(): Promise<void>;
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=generator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../src/generator.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,gBAAgB;IAC/B;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;IAElB;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;IAElB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IAErB;;OAEG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC/C;AAED,qBAAa,SAAS;IACpB,OAAO,CAAC,OAAO,CAA6B;gBAEhC,OAAO,EAAE,gBAAgB;IAWrC;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAgB7B;;OAEG;IACH,OAAO,CAAC,eAAe;IAUvB;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CA2FhC"}
|
|
@@ -0,0 +1,161 @@
|
|
|
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.Generator = void 0;
|
|
37
|
+
const child_process_1 = require("child_process");
|
|
38
|
+
const fs = __importStar(require("fs"));
|
|
39
|
+
const path = __importStar(require("path"));
|
|
40
|
+
const post_processor_1 = require("./post-processor");
|
|
41
|
+
class Generator {
|
|
42
|
+
constructor(options) {
|
|
43
|
+
this.options = {
|
|
44
|
+
templateDir: this.getDefaultTemplateDir(),
|
|
45
|
+
modelsOnly: false,
|
|
46
|
+
additionalProperties: {},
|
|
47
|
+
...options
|
|
48
|
+
};
|
|
49
|
+
this.validateOptions();
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Get the default template directory (bundled with the package)
|
|
53
|
+
*/
|
|
54
|
+
getDefaultTemplateDir() {
|
|
55
|
+
// In development, templates are in the root
|
|
56
|
+
// After build, they should be adjacent to dist
|
|
57
|
+
const devPath = path.join(__dirname, '../templates');
|
|
58
|
+
const prodPath = path.join(__dirname, '../../templates');
|
|
59
|
+
if (fs.existsSync(devPath)) {
|
|
60
|
+
return devPath;
|
|
61
|
+
}
|
|
62
|
+
if (fs.existsSync(prodPath)) {
|
|
63
|
+
return prodPath;
|
|
64
|
+
}
|
|
65
|
+
throw new Error('Could not find templates directory');
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Validate generator options
|
|
69
|
+
*/
|
|
70
|
+
validateOptions() {
|
|
71
|
+
if (!fs.existsSync(this.options.inputSpec)) {
|
|
72
|
+
throw new Error(`Input spec not found: ${this.options.inputSpec}`);
|
|
73
|
+
}
|
|
74
|
+
if (!fs.existsSync(this.options.templateDir)) {
|
|
75
|
+
throw new Error(`Template directory not found: ${this.options.templateDir}`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Generate TypeScript classes from OpenAPI specification
|
|
80
|
+
*/
|
|
81
|
+
async generate() {
|
|
82
|
+
try {
|
|
83
|
+
// Ensure output directory exists
|
|
84
|
+
fs.mkdirSync(this.options.outputDir, { recursive: true });
|
|
85
|
+
// Build additional properties string
|
|
86
|
+
const additionalProps = {
|
|
87
|
+
withSeparateModelsAndApi: 'true',
|
|
88
|
+
modelPackage: 'models',
|
|
89
|
+
apiPackage: 'api',
|
|
90
|
+
generateAliasAsModel: 'true',
|
|
91
|
+
supportsES6: 'true',
|
|
92
|
+
useSingleRequestParameter: 'true',
|
|
93
|
+
withNodeImports: 'true',
|
|
94
|
+
...this.options.additionalProperties
|
|
95
|
+
};
|
|
96
|
+
const propsString = Object.entries(additionalProps)
|
|
97
|
+
.map(([key, value]) => `${key}=${value}`)
|
|
98
|
+
.join(',');
|
|
99
|
+
// Run OpenAPI Generator
|
|
100
|
+
// Try to use system-installed openapi-generator first, fallback to npx
|
|
101
|
+
const commandParts = [
|
|
102
|
+
'openapi-generator',
|
|
103
|
+
'generate',
|
|
104
|
+
`-i "${this.options.inputSpec}"`,
|
|
105
|
+
'-g typescript-axios',
|
|
106
|
+
`-o "${this.options.outputDir}"`,
|
|
107
|
+
`-t "${this.options.templateDir}"`,
|
|
108
|
+
`--additional-properties=${propsString}`
|
|
109
|
+
];
|
|
110
|
+
// Add global-property to generate only models if modelsOnly is true
|
|
111
|
+
if (this.options.modelsOnly) {
|
|
112
|
+
commandParts.push('--global-property models');
|
|
113
|
+
}
|
|
114
|
+
const command = commandParts.join(' ');
|
|
115
|
+
console.log('Running OpenAPI Generator...');
|
|
116
|
+
// Ensure PATH includes common binary locations (Homebrew, system binaries)
|
|
117
|
+
const enhancedEnv = {
|
|
118
|
+
...process.env,
|
|
119
|
+
PATH: `/opt/homebrew/bin:/usr/local/bin:${process.env.PATH || ''}`
|
|
120
|
+
};
|
|
121
|
+
try {
|
|
122
|
+
(0, child_process_1.execSync)(command, { stdio: 'inherit', env: enhancedEnv }); // Temporarily use inherit to see output
|
|
123
|
+
}
|
|
124
|
+
catch (error) {
|
|
125
|
+
// Log the actual error for debugging
|
|
126
|
+
console.error('First command failed:', error instanceof Error ? error.message : error);
|
|
127
|
+
// If openapi-generator not found, try npx
|
|
128
|
+
const npxCommandParts = [
|
|
129
|
+
'npx',
|
|
130
|
+
'-y',
|
|
131
|
+
'@openapitools/openapi-generator-cli',
|
|
132
|
+
'generate',
|
|
133
|
+
`-i "${this.options.inputSpec}"`,
|
|
134
|
+
'-g typescript-axios',
|
|
135
|
+
`-o "${this.options.outputDir}"`,
|
|
136
|
+
`-t "${this.options.templateDir}"`,
|
|
137
|
+
`--additional-properties=${propsString}`
|
|
138
|
+
];
|
|
139
|
+
// Add global-property to generate only models if modelsOnly is true
|
|
140
|
+
if (this.options.modelsOnly) {
|
|
141
|
+
npxCommandParts.push('--global-property models');
|
|
142
|
+
}
|
|
143
|
+
const npxCommand = npxCommandParts.join(' ');
|
|
144
|
+
(0, child_process_1.execSync)(npxCommand, { stdio: 'pipe', env: enhancedEnv });
|
|
145
|
+
}
|
|
146
|
+
// Post-process generated files
|
|
147
|
+
console.log('Post-processing generated files...');
|
|
148
|
+
const postProcessor = new post_processor_1.PostProcessor(this.options.inputSpec, this.options.outputDir);
|
|
149
|
+
await postProcessor.process();
|
|
150
|
+
console.log('Generation complete!');
|
|
151
|
+
}
|
|
152
|
+
catch (error) {
|
|
153
|
+
if (error instanceof Error) {
|
|
154
|
+
throw new Error(`Failed to generate classes: ${error.message}`);
|
|
155
|
+
}
|
|
156
|
+
throw error;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
exports.Generator = Generator;
|
|
161
|
+
//# sourceMappingURL=generator.js.map
|