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 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,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -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
@@ -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