ts-class-to-openapi 1.0.3 → 1.0.5
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 +258 -33
- package/dist/__test__/circular-reference.test.d.ts +1 -0
- package/dist/__test__/entities/circular.entity.d.ts +59 -0
- package/dist/__test__/entities/complex-generics.entity.d.ts +33 -0
- package/dist/__test__/entities/comprehensive-enum.entity.d.ts +23 -0
- package/dist/__test__/entities/enum.entity.d.ts +29 -0
- package/dist/__test__/entities/user-role-generic.entity.d.ts +13 -0
- package/dist/__test__/enum.test.d.ts +1 -0
- package/dist/__test__/generic-types.test.d.ts +1 -0
- package/dist/__test__/index.d.ts +5 -0
- package/dist/__test__/ref-pattern.test.d.ts +1 -0
- package/dist/__test__/singleton-behavior.test.d.ts +1 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.esm.js +785 -45
- package/dist/index.js +785 -44
- package/dist/run.js +785 -44
- package/dist/transformer.d.ts +269 -28
- package/dist/transformer.fixtures.d.ts +4 -0
- package/dist/types.d.ts +17 -3
- package/package.json +1 -1
package/dist/run.js
CHANGED
|
@@ -38,6 +38,7 @@ const validatorDecorators = {
|
|
|
38
38
|
ArrayNotEmpty: { name: 'ArrayNotEmpty' },
|
|
39
39
|
ArrayMaxSize: { name: 'ArrayMaxSize' },
|
|
40
40
|
ArrayMinSize: { name: 'ArrayMinSize' },
|
|
41
|
+
IsEnum: { name: 'IsEnum', type: 'string' },
|
|
41
42
|
};
|
|
42
43
|
const constants = {
|
|
43
44
|
TS_CONFIG_DEFAULT_PATH,
|
|
@@ -96,6 +97,12 @@ class SchemaTransformer {
|
|
|
96
97
|
* @private
|
|
97
98
|
*/
|
|
98
99
|
loadedFiles = new Set();
|
|
100
|
+
/**
|
|
101
|
+
* Set of class names currently being processed to prevent circular references
|
|
102
|
+
* Key format: "fileName:className" for uniqueness across different files
|
|
103
|
+
* @private
|
|
104
|
+
*/
|
|
105
|
+
processingClasses = new Set();
|
|
99
106
|
/**
|
|
100
107
|
* Private constructor for singleton pattern.
|
|
101
108
|
*
|
|
@@ -148,20 +155,19 @@ class SchemaTransformer {
|
|
|
148
155
|
}
|
|
149
156
|
}
|
|
150
157
|
/**
|
|
151
|
-
*
|
|
158
|
+
* Transforms a class by its name into an OpenAPI schema object.
|
|
159
|
+
* Considers the context of the calling file to resolve ambiguous class names.
|
|
160
|
+
* Includes circular reference detection to prevent infinite recursion.
|
|
152
161
|
*
|
|
153
|
-
* @param className - The name of the class to
|
|
154
|
-
* @param
|
|
155
|
-
* @returns
|
|
162
|
+
* @param className - The name of the class to transform
|
|
163
|
+
* @param contextFilePath - Optional path to context file for resolving class ambiguity
|
|
164
|
+
* @returns Object containing the class name and its corresponding JSON schema
|
|
165
|
+
* @throws {Error} When the specified class cannot be found
|
|
156
166
|
* @private
|
|
157
167
|
*/
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
return sourceFile ? [sourceFile] : [];
|
|
162
|
-
}
|
|
163
|
-
// Only get source files that are not declaration files and not in node_modules
|
|
164
|
-
return this.program.getSourceFiles().filter(sf => {
|
|
168
|
+
transformByName(className, contextFilePath) {
|
|
169
|
+
// Get all relevant source files (not declaration files and not in node_modules)
|
|
170
|
+
const sourceFiles = this.program.getSourceFiles().filter(sf => {
|
|
165
171
|
if (sf.isDeclarationFile)
|
|
166
172
|
return false;
|
|
167
173
|
if (sf.fileName.includes('.d.ts'))
|
|
@@ -172,19 +178,46 @@ class SchemaTransformer {
|
|
|
172
178
|
this.loadedFiles.add(sf.fileName);
|
|
173
179
|
return true;
|
|
174
180
|
});
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
181
|
+
// If we have a context file, try to find the class in that file first
|
|
182
|
+
if (contextFilePath) {
|
|
183
|
+
const contextSourceFile = this.program.getSourceFile(contextFilePath);
|
|
184
|
+
if (contextSourceFile) {
|
|
185
|
+
const classNode = this.findClassByName(contextSourceFile, className);
|
|
186
|
+
if (classNode) {
|
|
187
|
+
const cacheKey = this.getCacheKey(contextSourceFile.fileName, className);
|
|
188
|
+
// Check cache first
|
|
189
|
+
if (this.classCache.has(cacheKey)) {
|
|
190
|
+
return this.classCache.get(cacheKey);
|
|
191
|
+
}
|
|
192
|
+
// Check for circular reference before processing
|
|
193
|
+
if (this.processingClasses.has(cacheKey)) {
|
|
194
|
+
// Return a $ref reference to break circular dependency (OpenAPI 3.1 style)
|
|
195
|
+
return {
|
|
196
|
+
name: className,
|
|
197
|
+
schema: {
|
|
198
|
+
$ref: `#/components/schemas/${className}`,
|
|
199
|
+
description: `Reference to ${className} (circular reference detected)`,
|
|
200
|
+
},
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
// Mark this class as being processed
|
|
204
|
+
this.processingClasses.add(cacheKey);
|
|
205
|
+
try {
|
|
206
|
+
const result = this.transformClass(classNode, contextSourceFile);
|
|
207
|
+
this.classCache.set(cacheKey, result);
|
|
208
|
+
this.cleanupCache();
|
|
209
|
+
return result;
|
|
210
|
+
}
|
|
211
|
+
finally {
|
|
212
|
+
// Always remove from processing set when done
|
|
213
|
+
this.processingClasses.delete(cacheKey);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
// Fallback to searching all files, but prioritize files that are more likely to be relevant
|
|
219
|
+
const prioritizedFiles = this.prioritizeSourceFiles(sourceFiles, contextFilePath);
|
|
220
|
+
for (const sourceFile of prioritizedFiles) {
|
|
188
221
|
const classNode = this.findClassByName(sourceFile, className);
|
|
189
222
|
if (classNode && sourceFile?.fileName) {
|
|
190
223
|
const cacheKey = this.getCacheKey(sourceFile.fileName, className);
|
|
@@ -192,16 +225,67 @@ class SchemaTransformer {
|
|
|
192
225
|
if (this.classCache.has(cacheKey)) {
|
|
193
226
|
return this.classCache.get(cacheKey);
|
|
194
227
|
}
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
228
|
+
// Check for circular reference before processing
|
|
229
|
+
if (this.processingClasses.has(cacheKey)) {
|
|
230
|
+
// Return a $ref reference to break circular dependency (OpenAPI 3.1 style)
|
|
231
|
+
return {
|
|
232
|
+
name: className,
|
|
233
|
+
schema: {
|
|
234
|
+
$ref: `#/components/schemas/${className}`,
|
|
235
|
+
description: `Reference to ${className} (circular reference detected)`,
|
|
236
|
+
},
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
// Mark this class as being processed
|
|
240
|
+
this.processingClasses.add(cacheKey);
|
|
241
|
+
try {
|
|
242
|
+
const result = this.transformClass(classNode, sourceFile);
|
|
243
|
+
// Cache using fileName:className as key for uniqueness
|
|
244
|
+
this.classCache.set(cacheKey, result);
|
|
245
|
+
// Clean up cache if it gets too large
|
|
246
|
+
this.cleanupCache();
|
|
247
|
+
return result;
|
|
248
|
+
}
|
|
249
|
+
finally {
|
|
250
|
+
// Always remove from processing set when done
|
|
251
|
+
this.processingClasses.delete(cacheKey);
|
|
252
|
+
}
|
|
201
253
|
}
|
|
202
254
|
}
|
|
203
255
|
throw new Error(`Class ${className} not found`);
|
|
204
256
|
}
|
|
257
|
+
/**
|
|
258
|
+
* Prioritizes source files based on context to resolve class name conflicts.
|
|
259
|
+
* Gives priority to files in the same directory or with similar names.
|
|
260
|
+
*
|
|
261
|
+
* @param sourceFiles - Array of source files to prioritize
|
|
262
|
+
* @param contextFilePath - Optional path to context file for prioritization
|
|
263
|
+
* @returns Prioritized array of source files
|
|
264
|
+
* @private
|
|
265
|
+
*/
|
|
266
|
+
prioritizeSourceFiles(sourceFiles, contextFilePath) {
|
|
267
|
+
if (!contextFilePath) {
|
|
268
|
+
return sourceFiles;
|
|
269
|
+
}
|
|
270
|
+
const contextDir = contextFilePath.substring(0, contextFilePath.lastIndexOf('/'));
|
|
271
|
+
return sourceFiles.sort((a, b) => {
|
|
272
|
+
const aDir = a.fileName.substring(0, a.fileName.lastIndexOf('/'));
|
|
273
|
+
const bDir = b.fileName.substring(0, b.fileName.lastIndexOf('/'));
|
|
274
|
+
// Prioritize files in the same directory as context
|
|
275
|
+
const aInSameDir = aDir === contextDir ? 1 : 0;
|
|
276
|
+
const bInSameDir = bDir === contextDir ? 1 : 0;
|
|
277
|
+
if (aInSameDir !== bInSameDir) {
|
|
278
|
+
return bInSameDir - aInSameDir; // Higher priority first
|
|
279
|
+
}
|
|
280
|
+
// Prioritize non-test files over test files
|
|
281
|
+
const aIsTest = a.fileName.includes('test') || a.fileName.includes('spec') ? 0 : 1;
|
|
282
|
+
const bIsTest = b.fileName.includes('test') || b.fileName.includes('spec') ? 0 : 1;
|
|
283
|
+
if (aIsTest !== bIsTest) {
|
|
284
|
+
return bIsTest - aIsTest; // Non-test files first
|
|
285
|
+
}
|
|
286
|
+
return 0;
|
|
287
|
+
});
|
|
288
|
+
}
|
|
205
289
|
/**
|
|
206
290
|
* Gets the singleton instance of SchemaTransformer.
|
|
207
291
|
*
|
|
@@ -228,16 +312,88 @@ class SchemaTransformer {
|
|
|
228
312
|
/**
|
|
229
313
|
* Clears the current singleton instance. Useful for testing or when you need
|
|
230
314
|
* to create a new instance with different configuration.
|
|
315
|
+
* @private
|
|
231
316
|
*/
|
|
232
317
|
static clearInstance() {
|
|
233
|
-
SchemaTransformer.instance =
|
|
318
|
+
SchemaTransformer.instance = undefined;
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* Flag to prevent recursive disposal calls
|
|
322
|
+
* @private
|
|
323
|
+
*/
|
|
324
|
+
static disposingInProgress = false;
|
|
325
|
+
/**
|
|
326
|
+
* Completely disposes of the current singleton instance and releases all resources.
|
|
327
|
+
* This is a static method that can be called without having an instance reference.
|
|
328
|
+
* Ensures complete memory cleanup regardless of the current state.
|
|
329
|
+
*
|
|
330
|
+
* @example
|
|
331
|
+
* ```typescript
|
|
332
|
+
* SchemaTransformer.disposeInstance();
|
|
333
|
+
* // All resources released, next getInstance() will create fresh instance
|
|
334
|
+
* ```
|
|
335
|
+
*
|
|
336
|
+
* @public
|
|
337
|
+
*/
|
|
338
|
+
static disposeInstance() {
|
|
339
|
+
// Prevent recursive disposal calls
|
|
340
|
+
if (SchemaTransformer.disposingInProgress) {
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
SchemaTransformer.disposingInProgress = true;
|
|
344
|
+
try {
|
|
345
|
+
if (SchemaTransformer.instance) {
|
|
346
|
+
SchemaTransformer.instance.dispose();
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
catch (error) {
|
|
350
|
+
// Log any disposal errors but continue with cleanup
|
|
351
|
+
console.warn('Warning during static disposal:', error);
|
|
352
|
+
}
|
|
353
|
+
finally {
|
|
354
|
+
// Always ensure the static instance is cleared
|
|
355
|
+
SchemaTransformer.instance = undefined;
|
|
356
|
+
SchemaTransformer.disposingInProgress = false;
|
|
357
|
+
// Force garbage collection for cleanup
|
|
358
|
+
if (global.gc) {
|
|
359
|
+
global.gc();
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* @deprecated Use disposeInstance() instead for better clarity
|
|
365
|
+
* @private
|
|
366
|
+
*/
|
|
367
|
+
static dispose() {
|
|
368
|
+
SchemaTransformer.disposeInstance();
|
|
234
369
|
}
|
|
235
370
|
static getInstance(tsConfigPath, options) {
|
|
236
|
-
if (!SchemaTransformer.instance) {
|
|
371
|
+
if (!SchemaTransformer.instance || SchemaTransformer.isInstanceDisposed()) {
|
|
237
372
|
SchemaTransformer.instance = new SchemaTransformer(tsConfigPath, options);
|
|
238
373
|
}
|
|
239
374
|
return SchemaTransformer.instance;
|
|
240
375
|
}
|
|
376
|
+
/**
|
|
377
|
+
* Internal method to check if current instance is disposed
|
|
378
|
+
* @private
|
|
379
|
+
*/
|
|
380
|
+
static isInstanceDisposed() {
|
|
381
|
+
return SchemaTransformer.instance
|
|
382
|
+
? SchemaTransformer.instance.isDisposed()
|
|
383
|
+
: true;
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* Transforms a class using the singleton instance
|
|
387
|
+
* @param cls - The class constructor function to transform
|
|
388
|
+
* @param options - Optional configuration for memory management (only used if no instance exists)
|
|
389
|
+
* @returns Object containing the class name and its corresponding JSON schema
|
|
390
|
+
* @public
|
|
391
|
+
*/
|
|
392
|
+
static transformClass(cls, options) {
|
|
393
|
+
// Use the singleton instance instead of creating a temporary one
|
|
394
|
+
const transformer = SchemaTransformer.getInstance(undefined, options);
|
|
395
|
+
return transformer.transform(cls);
|
|
396
|
+
}
|
|
241
397
|
/**
|
|
242
398
|
* Transforms a class constructor function into an OpenAPI schema object.
|
|
243
399
|
*
|
|
@@ -272,31 +428,147 @@ class SchemaTransformer {
|
|
|
272
428
|
clearCache() {
|
|
273
429
|
this.classCache.clear();
|
|
274
430
|
this.loadedFiles.clear();
|
|
431
|
+
this.processingClasses.clear();
|
|
275
432
|
// Force garbage collection hint if available
|
|
276
433
|
if (global.gc) {
|
|
277
434
|
global.gc();
|
|
278
435
|
}
|
|
279
436
|
}
|
|
437
|
+
/**
|
|
438
|
+
* Completely disposes of the transformer instance and releases all resources.
|
|
439
|
+
* This includes clearing all caches, releasing TypeScript program resources,
|
|
440
|
+
* and resetting the singleton instance.
|
|
441
|
+
*
|
|
442
|
+
* After calling this method, you need to call getInstance() again to get a new instance.
|
|
443
|
+
*
|
|
444
|
+
* @example
|
|
445
|
+
* ```typescript
|
|
446
|
+
* const transformer = SchemaTransformer.getInstance();
|
|
447
|
+
* // ... use transformer
|
|
448
|
+
* transformer.dispose();
|
|
449
|
+
* // transformer is now unusable, need to get new instance
|
|
450
|
+
* const newTransformer = SchemaTransformer.getInstance();
|
|
451
|
+
* ```
|
|
452
|
+
*
|
|
453
|
+
* @private
|
|
454
|
+
*/
|
|
455
|
+
dispose() {
|
|
456
|
+
try {
|
|
457
|
+
// Clear all caches and sets completely
|
|
458
|
+
this.classCache.clear();
|
|
459
|
+
this.loadedFiles.clear();
|
|
460
|
+
this.processingClasses.clear();
|
|
461
|
+
// Release TypeScript program resources
|
|
462
|
+
// While TypeScript doesn't provide explicit disposal methods,
|
|
463
|
+
// we can help garbage collection by clearing all references
|
|
464
|
+
// Clear all references to TypeScript objects
|
|
465
|
+
// @ts-ignore - We're intentionally setting these to null for cleanup
|
|
466
|
+
this.program = null;
|
|
467
|
+
// @ts-ignore - We're intentionally setting these to null for cleanup
|
|
468
|
+
this.checker = null;
|
|
469
|
+
}
|
|
470
|
+
catch (error) {
|
|
471
|
+
// If there's any error during disposal, log it but continue
|
|
472
|
+
console.warn('Warning during transformer disposal:', error);
|
|
473
|
+
}
|
|
474
|
+
finally {
|
|
475
|
+
// Force garbage collection for cleanup
|
|
476
|
+
if (global.gc) {
|
|
477
|
+
global.gc();
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
/**
|
|
482
|
+
* Completely resets the transformer by disposing current instance and creating a new one.
|
|
483
|
+
* This is useful when you need a fresh start with different TypeScript configuration
|
|
484
|
+
* or want to ensure all resources are properly released and recreated.
|
|
485
|
+
*
|
|
486
|
+
* @param tsConfigPath - Optional path to a specific TypeScript config file for the new instance
|
|
487
|
+
* @param options - Configuration options for memory management for the new instance
|
|
488
|
+
* @returns A fresh SchemaTransformer instance
|
|
489
|
+
*
|
|
490
|
+
* @example
|
|
491
|
+
* ```typescript
|
|
492
|
+
* const transformer = SchemaTransformer.getInstance();
|
|
493
|
+
* // ... use transformer
|
|
494
|
+
* const freshTransformer = transformer.reset('./new-tsconfig.json');
|
|
495
|
+
* ```
|
|
496
|
+
*
|
|
497
|
+
* @private
|
|
498
|
+
*/
|
|
499
|
+
reset(tsConfigPath, options) {
|
|
500
|
+
// Dispose current instance using static method to properly clear instance reference
|
|
501
|
+
SchemaTransformer.disposeInstance();
|
|
502
|
+
// Create and return new instance
|
|
503
|
+
return SchemaTransformer.getInstance(tsConfigPath, options);
|
|
504
|
+
}
|
|
280
505
|
/**
|
|
281
506
|
* Gets memory usage statistics for monitoring and debugging.
|
|
282
507
|
*
|
|
283
|
-
* @returns Object containing cache size
|
|
508
|
+
* @returns Object containing cache size, loaded files count, and processing status
|
|
284
509
|
*
|
|
285
510
|
* @example
|
|
286
511
|
* ```typescript
|
|
287
512
|
* const transformer = SchemaTransformer.getInstance();
|
|
288
513
|
* const stats = transformer.getMemoryStats();
|
|
289
514
|
* console.log(`Cache entries: ${stats.cacheSize}, Files loaded: ${stats.loadedFiles}`);
|
|
515
|
+
* console.log(`Currently processing: ${stats.currentlyProcessing} classes`);
|
|
290
516
|
* ```
|
|
291
517
|
*
|
|
292
|
-
* @
|
|
518
|
+
* @private
|
|
293
519
|
*/
|
|
294
520
|
getMemoryStats() {
|
|
295
521
|
return {
|
|
296
|
-
cacheSize: this.classCache
|
|
297
|
-
loadedFiles: this.loadedFiles
|
|
522
|
+
cacheSize: this.classCache?.size || 0,
|
|
523
|
+
loadedFiles: this.loadedFiles?.size || 0,
|
|
524
|
+
currentlyProcessing: this.processingClasses?.size || 0,
|
|
525
|
+
maxCacheSize: this.maxCacheSize || 0,
|
|
526
|
+
autoCleanup: this.autoCleanup || false,
|
|
527
|
+
isDisposed: !this.program || !this.checker,
|
|
298
528
|
};
|
|
299
529
|
}
|
|
530
|
+
/**
|
|
531
|
+
* Checks if the transformer instance has been disposed and is no longer usable.
|
|
532
|
+
*
|
|
533
|
+
* @returns True if the instance has been disposed
|
|
534
|
+
*
|
|
535
|
+
* @example
|
|
536
|
+
* ```typescript
|
|
537
|
+
* const transformer = SchemaTransformer.getInstance();
|
|
538
|
+
* transformer.dispose();
|
|
539
|
+
* console.log(transformer.isDisposed()); // true
|
|
540
|
+
* ```
|
|
541
|
+
*
|
|
542
|
+
* @private
|
|
543
|
+
*/
|
|
544
|
+
isDisposed() {
|
|
545
|
+
return (!this.program ||
|
|
546
|
+
!this.checker ||
|
|
547
|
+
!this.classCache ||
|
|
548
|
+
!this.loadedFiles ||
|
|
549
|
+
!this.processingClasses);
|
|
550
|
+
}
|
|
551
|
+
/**
|
|
552
|
+
* Static method to check if there's an active singleton instance.
|
|
553
|
+
*
|
|
554
|
+
* @returns True if there's an active instance, false if disposed or never created
|
|
555
|
+
*
|
|
556
|
+
* @example
|
|
557
|
+
* ```typescript
|
|
558
|
+
* console.log(SchemaTransformer.hasActiveInstance()); // false
|
|
559
|
+
* const transformer = SchemaTransformer.getInstance();
|
|
560
|
+
* console.log(SchemaTransformer.hasActiveInstance()); // true
|
|
561
|
+
* SchemaTransformer.dispose();
|
|
562
|
+
* console.log(SchemaTransformer.hasActiveInstance()); // false
|
|
563
|
+
* ```
|
|
564
|
+
*
|
|
565
|
+
* @private
|
|
566
|
+
*/
|
|
567
|
+
static hasActiveInstance() {
|
|
568
|
+
return (SchemaTransformer.instance !== null &&
|
|
569
|
+
SchemaTransformer.instance !== undefined &&
|
|
570
|
+
!SchemaTransformer.isInstanceDisposed());
|
|
571
|
+
}
|
|
300
572
|
/**
|
|
301
573
|
* Finds a class declaration by name within a source file.
|
|
302
574
|
*
|
|
@@ -321,13 +593,14 @@ class SchemaTransformer {
|
|
|
321
593
|
* Transforms a TypeScript class declaration into a schema object.
|
|
322
594
|
*
|
|
323
595
|
* @param classNode - The TypeScript class declaration node
|
|
596
|
+
* @param sourceFile - The source file containing the class (for context)
|
|
324
597
|
* @returns Object containing class name and generated schema
|
|
325
598
|
* @private
|
|
326
599
|
*/
|
|
327
|
-
transformClass(classNode) {
|
|
600
|
+
transformClass(classNode, sourceFile) {
|
|
328
601
|
const className = classNode.name?.text || 'Unknown';
|
|
329
602
|
const properties = this.extractProperties(classNode);
|
|
330
|
-
const schema = this.generateSchema(properties);
|
|
603
|
+
const schema = this.generateSchema(properties, sourceFile?.fileName);
|
|
331
604
|
return { name: className, schema };
|
|
332
605
|
}
|
|
333
606
|
/**
|
|
@@ -371,6 +644,237 @@ class SchemaTransformer {
|
|
|
371
644
|
const type = this.checker.getTypeAtLocation(property);
|
|
372
645
|
return this.checker.typeToString(type);
|
|
373
646
|
}
|
|
647
|
+
/**
|
|
648
|
+
* Resolves generic types by analyzing the type alias and its arguments.
|
|
649
|
+
* For example, User<Role> where User is a type alias will be resolved to its structure.
|
|
650
|
+
*
|
|
651
|
+
* @param typeNode - The TypeScript type reference node with generic arguments
|
|
652
|
+
* @returns String representation of the resolved type or schema
|
|
653
|
+
* @private
|
|
654
|
+
*/
|
|
655
|
+
resolveGenericType(typeNode) {
|
|
656
|
+
const typeName = typeNode.typeName.text;
|
|
657
|
+
const typeArguments = typeNode.typeArguments;
|
|
658
|
+
if (!typeArguments || typeArguments.length === 0) {
|
|
659
|
+
return typeName;
|
|
660
|
+
}
|
|
661
|
+
// Try to resolve the type using the TypeScript type checker
|
|
662
|
+
const type = this.checker.getTypeAtLocation(typeNode);
|
|
663
|
+
const resolvedType = this.checker.typeToString(type);
|
|
664
|
+
// If we can resolve it to a meaningful structure, use that
|
|
665
|
+
if (resolvedType &&
|
|
666
|
+
resolvedType !== typeName &&
|
|
667
|
+
!resolvedType.includes('any')) {
|
|
668
|
+
// For type aliases like User<Role>, we want to create a synthetic type name
|
|
669
|
+
// that represents the resolved structure
|
|
670
|
+
const typeArgNames = typeArguments.map(arg => {
|
|
671
|
+
if (ts.isTypeReferenceNode(arg) && ts.isIdentifier(arg.typeName)) {
|
|
672
|
+
return arg.typeName.text;
|
|
673
|
+
}
|
|
674
|
+
return this.getTypeNodeToString(arg);
|
|
675
|
+
});
|
|
676
|
+
return `${typeName}_${typeArgNames.join('_')}`;
|
|
677
|
+
}
|
|
678
|
+
return typeName;
|
|
679
|
+
}
|
|
680
|
+
/**
|
|
681
|
+
* Checks if a type string represents a resolved generic type.
|
|
682
|
+
*
|
|
683
|
+
* @param type - The type string to check
|
|
684
|
+
* @returns True if it's a resolved generic type
|
|
685
|
+
* @private
|
|
686
|
+
*/
|
|
687
|
+
isResolvedGenericType(type) {
|
|
688
|
+
// Simple heuristic: resolved generic types contain underscores and
|
|
689
|
+
// the parts after underscore should be known types
|
|
690
|
+
const parts = type.split('_');
|
|
691
|
+
return (parts.length > 1 &&
|
|
692
|
+
parts
|
|
693
|
+
.slice(1)
|
|
694
|
+
.every(part => this.isKnownType(part) || this.isPrimitiveType(part)));
|
|
695
|
+
}
|
|
696
|
+
/**
|
|
697
|
+
* Checks if a type is a known class or interface.
|
|
698
|
+
*
|
|
699
|
+
* @param typeName - The type name to check
|
|
700
|
+
* @returns True if it's a known type
|
|
701
|
+
* @private
|
|
702
|
+
*/
|
|
703
|
+
isKnownType(typeName) {
|
|
704
|
+
// First check if it's a primitive type to avoid unnecessary lookups
|
|
705
|
+
if (this.isPrimitiveType(typeName)) {
|
|
706
|
+
return true;
|
|
707
|
+
}
|
|
708
|
+
try {
|
|
709
|
+
// Use a more conservative approach - check if we can find the class
|
|
710
|
+
// without actually transforming it to avoid side effects
|
|
711
|
+
const found = this.findClassInProject(typeName);
|
|
712
|
+
return found !== null;
|
|
713
|
+
}
|
|
714
|
+
catch {
|
|
715
|
+
return false;
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
/**
|
|
719
|
+
* Finds a class by name in the project without transforming it.
|
|
720
|
+
*
|
|
721
|
+
* @param className - The class name to find
|
|
722
|
+
* @returns True if found, false otherwise
|
|
723
|
+
* @private
|
|
724
|
+
*/
|
|
725
|
+
findClassInProject(className) {
|
|
726
|
+
const sourceFiles = this.program.getSourceFiles().filter(sf => {
|
|
727
|
+
if (sf.isDeclarationFile)
|
|
728
|
+
return false;
|
|
729
|
+
if (sf.fileName.includes('.d.ts'))
|
|
730
|
+
return false;
|
|
731
|
+
if (sf.fileName.includes('node_modules'))
|
|
732
|
+
return false;
|
|
733
|
+
return true;
|
|
734
|
+
});
|
|
735
|
+
for (const sourceFile of sourceFiles) {
|
|
736
|
+
const found = this.findClassByName(sourceFile, className);
|
|
737
|
+
if (found)
|
|
738
|
+
return true;
|
|
739
|
+
}
|
|
740
|
+
return false;
|
|
741
|
+
}
|
|
742
|
+
/**
|
|
743
|
+
* Checks if a type is a primitive type.
|
|
744
|
+
*
|
|
745
|
+
* @param typeName - The type name to check
|
|
746
|
+
* @returns True if it's a primitive type
|
|
747
|
+
* @private
|
|
748
|
+
*/
|
|
749
|
+
isPrimitiveType(typeName) {
|
|
750
|
+
const lowerTypeName = typeName.toLowerCase();
|
|
751
|
+
// Check against all primitive types from constants
|
|
752
|
+
const primitiveTypes = [
|
|
753
|
+
constants.jsPrimitives.String.type.toLowerCase(),
|
|
754
|
+
constants.jsPrimitives.Number.type.toLowerCase(),
|
|
755
|
+
constants.jsPrimitives.Boolean.type.toLowerCase(),
|
|
756
|
+
constants.jsPrimitives.Date.type.toLowerCase(),
|
|
757
|
+
constants.jsPrimitives.Buffer.type.toLowerCase(),
|
|
758
|
+
constants.jsPrimitives.Uint8Array.type.toLowerCase(),
|
|
759
|
+
constants.jsPrimitives.File.type.toLowerCase(),
|
|
760
|
+
constants.jsPrimitives.UploadFile.type.toLowerCase(),
|
|
761
|
+
constants.jsPrimitives.BigInt.type.toLowerCase(),
|
|
762
|
+
];
|
|
763
|
+
return primitiveTypes.includes(lowerTypeName);
|
|
764
|
+
}
|
|
765
|
+
/**
|
|
766
|
+
* Resolves a generic type schema by analyzing the type alias structure.
|
|
767
|
+
*
|
|
768
|
+
* @param resolvedTypeName - The resolved generic type name (e.g., User_Role)
|
|
769
|
+
* @returns OpenAPI schema for the resolved generic type
|
|
770
|
+
* @private
|
|
771
|
+
*/
|
|
772
|
+
resolveGenericTypeSchema(resolvedTypeName) {
|
|
773
|
+
const parts = resolvedTypeName.split('_');
|
|
774
|
+
const baseTypeName = parts[0];
|
|
775
|
+
const typeArgNames = parts.slice(1);
|
|
776
|
+
if (!baseTypeName) {
|
|
777
|
+
return null;
|
|
778
|
+
}
|
|
779
|
+
// Find the original type alias declaration
|
|
780
|
+
const typeAliasSymbol = this.findTypeAliasDeclaration(baseTypeName);
|
|
781
|
+
if (!typeAliasSymbol) {
|
|
782
|
+
return null;
|
|
783
|
+
}
|
|
784
|
+
// Create a schema based on the type alias structure, substituting type parameters
|
|
785
|
+
return this.createSchemaFromTypeAlias(typeAliasSymbol, typeArgNames);
|
|
786
|
+
}
|
|
787
|
+
/**
|
|
788
|
+
* Finds a type alias declaration by name.
|
|
789
|
+
*
|
|
790
|
+
* @param typeName - The type alias name to find
|
|
791
|
+
* @returns The type alias declaration node or null
|
|
792
|
+
* @private
|
|
793
|
+
*/
|
|
794
|
+
findTypeAliasDeclaration(typeName) {
|
|
795
|
+
for (const sourceFile of this.program.getSourceFiles()) {
|
|
796
|
+
if (sourceFile.isDeclarationFile)
|
|
797
|
+
continue;
|
|
798
|
+
const findTypeAlias = (node) => {
|
|
799
|
+
if (ts.isTypeAliasDeclaration(node) && node.name.text === typeName) {
|
|
800
|
+
return node;
|
|
801
|
+
}
|
|
802
|
+
return ts.forEachChild(node, findTypeAlias) || null;
|
|
803
|
+
};
|
|
804
|
+
const result = findTypeAlias(sourceFile);
|
|
805
|
+
if (result)
|
|
806
|
+
return result;
|
|
807
|
+
}
|
|
808
|
+
return null;
|
|
809
|
+
}
|
|
810
|
+
/**
|
|
811
|
+
* Creates a schema from a type alias declaration, substituting type parameters.
|
|
812
|
+
*
|
|
813
|
+
* @param typeAlias - The type alias declaration
|
|
814
|
+
* @param typeArgNames - The concrete type arguments
|
|
815
|
+
* @returns OpenAPI schema for the type alias
|
|
816
|
+
* @private
|
|
817
|
+
*/
|
|
818
|
+
createSchemaFromTypeAlias(typeAlias, typeArgNames) {
|
|
819
|
+
const typeNode = typeAlias.type;
|
|
820
|
+
if (ts.isTypeLiteralNode(typeNode)) {
|
|
821
|
+
const schema = {
|
|
822
|
+
type: 'object',
|
|
823
|
+
properties: {},
|
|
824
|
+
required: [],
|
|
825
|
+
};
|
|
826
|
+
for (const member of typeNode.members) {
|
|
827
|
+
if (ts.isPropertySignature(member) &&
|
|
828
|
+
member.name &&
|
|
829
|
+
ts.isIdentifier(member.name)) {
|
|
830
|
+
const propertyName = member.name.text;
|
|
831
|
+
const isOptional = !!member.questionToken;
|
|
832
|
+
if (member.type) {
|
|
833
|
+
const propertyType = this.resolveTypeParameterInTypeAlias(member.type, typeAlias.typeParameters, typeArgNames);
|
|
834
|
+
const { type, format, nestedSchema } = this.mapTypeToSchema(propertyType);
|
|
835
|
+
if (nestedSchema) {
|
|
836
|
+
schema.properties[propertyName] = nestedSchema;
|
|
837
|
+
}
|
|
838
|
+
else {
|
|
839
|
+
schema.properties[propertyName] = { type };
|
|
840
|
+
if (format)
|
|
841
|
+
schema.properties[propertyName].format = format;
|
|
842
|
+
}
|
|
843
|
+
if (!isOptional) {
|
|
844
|
+
schema.required.push(propertyName);
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
return schema;
|
|
850
|
+
}
|
|
851
|
+
return null;
|
|
852
|
+
}
|
|
853
|
+
/**
|
|
854
|
+
* Resolves type parameters in a type alias to concrete types.
|
|
855
|
+
*
|
|
856
|
+
* @param typeNode - The type node to resolve
|
|
857
|
+
* @param typeParameters - The type parameters of the type alias
|
|
858
|
+
* @param typeArgNames - The concrete type arguments
|
|
859
|
+
* @returns The resolved type string
|
|
860
|
+
* @private
|
|
861
|
+
*/
|
|
862
|
+
resolveTypeParameterInTypeAlias(typeNode, typeParameters, typeArgNames) {
|
|
863
|
+
if (ts.isTypeReferenceNode(typeNode) &&
|
|
864
|
+
ts.isIdentifier(typeNode.typeName)) {
|
|
865
|
+
const typeName = typeNode.typeName.text;
|
|
866
|
+
// Check if this is a type parameter
|
|
867
|
+
if (typeParameters) {
|
|
868
|
+
const paramIndex = typeParameters.findIndex(param => param.name.text === typeName);
|
|
869
|
+
if (paramIndex !== -1 && paramIndex < typeArgNames.length) {
|
|
870
|
+
const resolvedType = typeArgNames[paramIndex];
|
|
871
|
+
return resolvedType || typeName;
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
return typeName;
|
|
875
|
+
}
|
|
876
|
+
return this.getTypeNodeToString(typeNode);
|
|
877
|
+
}
|
|
374
878
|
/**
|
|
375
879
|
* Converts a TypeScript type node to its string representation.
|
|
376
880
|
*
|
|
@@ -396,6 +900,7 @@ class SchemaTransformer {
|
|
|
396
900
|
return firstTypeArg.typeName.text;
|
|
397
901
|
}
|
|
398
902
|
}
|
|
903
|
+
return this.resolveGenericType(typeNode);
|
|
399
904
|
}
|
|
400
905
|
return typeNode.typeName.text;
|
|
401
906
|
}
|
|
@@ -494,19 +999,24 @@ class SchemaTransformer {
|
|
|
494
999
|
* Generates an OpenAPI schema from extracted property information.
|
|
495
1000
|
*
|
|
496
1001
|
* @param properties - Array of property information to process
|
|
1002
|
+
* @param contextFilePath - Optional context file path for resolving class references
|
|
497
1003
|
* @returns Complete OpenAPI schema object with properties and validation rules
|
|
498
1004
|
* @private
|
|
499
1005
|
*/
|
|
500
|
-
generateSchema(properties) {
|
|
1006
|
+
generateSchema(properties, contextFilePath) {
|
|
501
1007
|
const schema = {
|
|
502
1008
|
type: 'object',
|
|
503
1009
|
properties: {},
|
|
504
1010
|
required: [],
|
|
505
1011
|
};
|
|
506
1012
|
for (const property of properties) {
|
|
507
|
-
const { type, format, nestedSchema } = this.mapTypeToSchema(property.type);
|
|
1013
|
+
const { type, format, nestedSchema } = this.mapTypeToSchema(property.type, contextFilePath);
|
|
508
1014
|
if (nestedSchema) {
|
|
509
1015
|
schema.properties[property.name] = nestedSchema;
|
|
1016
|
+
// Skip decorator application for $ref schemas
|
|
1017
|
+
if (this.isRefSchema(nestedSchema)) {
|
|
1018
|
+
continue;
|
|
1019
|
+
}
|
|
510
1020
|
}
|
|
511
1021
|
else {
|
|
512
1022
|
schema.properties[property.name] = { type };
|
|
@@ -529,14 +1039,15 @@ class SchemaTransformer {
|
|
|
529
1039
|
* Handles primitive types, arrays, and nested objects recursively.
|
|
530
1040
|
*
|
|
531
1041
|
* @param type - The TypeScript type string to map
|
|
1042
|
+
* @param contextFilePath - Optional context file path for resolving class references
|
|
532
1043
|
* @returns Object containing OpenAPI type, optional format, and nested schema
|
|
533
1044
|
* @private
|
|
534
1045
|
*/
|
|
535
|
-
mapTypeToSchema(type) {
|
|
1046
|
+
mapTypeToSchema(type, contextFilePath) {
|
|
536
1047
|
// Handle arrays
|
|
537
1048
|
if (type.endsWith('[]')) {
|
|
538
1049
|
const elementType = type.slice(0, -2);
|
|
539
|
-
const elementSchema = this.mapTypeToSchema(elementType);
|
|
1050
|
+
const elementSchema = this.mapTypeToSchema(elementType, contextFilePath);
|
|
540
1051
|
const items = elementSchema.nestedSchema || {
|
|
541
1052
|
type: elementSchema.type,
|
|
542
1053
|
};
|
|
@@ -580,9 +1091,31 @@ class SchemaTransformer {
|
|
|
580
1091
|
format: constants.jsPrimitives.UploadFile.format,
|
|
581
1092
|
};
|
|
582
1093
|
default:
|
|
1094
|
+
// Check if it's a resolved generic type (e.g., User_Role)
|
|
1095
|
+
if (type.includes('_') && this.isResolvedGenericType(type)) {
|
|
1096
|
+
try {
|
|
1097
|
+
const genericSchema = this.resolveGenericTypeSchema(type);
|
|
1098
|
+
if (genericSchema) {
|
|
1099
|
+
return {
|
|
1100
|
+
type: constants.jsPrimitives.Object.value,
|
|
1101
|
+
nestedSchema: genericSchema,
|
|
1102
|
+
};
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
catch (error) {
|
|
1106
|
+
console.warn(`Failed to resolve generic type ${type}:`, error);
|
|
1107
|
+
}
|
|
1108
|
+
}
|
|
583
1109
|
// Handle nested objects
|
|
584
1110
|
try {
|
|
585
|
-
const nestedResult = this.transformByName(type);
|
|
1111
|
+
const nestedResult = this.transformByName(type, contextFilePath);
|
|
1112
|
+
// Check if it's a $ref schema (circular reference)
|
|
1113
|
+
if (nestedResult.schema.$ref) {
|
|
1114
|
+
return {
|
|
1115
|
+
type: constants.jsPrimitives.Object.value,
|
|
1116
|
+
nestedSchema: nestedResult.schema,
|
|
1117
|
+
};
|
|
1118
|
+
}
|
|
586
1119
|
return {
|
|
587
1120
|
type: constants.jsPrimitives.Object.value,
|
|
588
1121
|
nestedSchema: nestedResult.schema,
|
|
@@ -593,6 +1126,16 @@ class SchemaTransformer {
|
|
|
593
1126
|
}
|
|
594
1127
|
}
|
|
595
1128
|
}
|
|
1129
|
+
/**
|
|
1130
|
+
* Checks if a schema is a $ref schema (circular reference).
|
|
1131
|
+
*
|
|
1132
|
+
* @param schema - The schema to check
|
|
1133
|
+
* @returns True if it's a $ref schema
|
|
1134
|
+
* @private
|
|
1135
|
+
*/
|
|
1136
|
+
isRefSchema(schema) {
|
|
1137
|
+
return '$ref' in schema;
|
|
1138
|
+
}
|
|
596
1139
|
/**
|
|
597
1140
|
* Applies class-validator decorators to schema properties.
|
|
598
1141
|
* Maps validation decorators to their corresponding OpenAPI schema constraints.
|
|
@@ -603,6 +1146,10 @@ class SchemaTransformer {
|
|
|
603
1146
|
* @private
|
|
604
1147
|
*/
|
|
605
1148
|
applyDecorators(decorators, schema, propertyName) {
|
|
1149
|
+
// Skip applying decorators to $ref schemas
|
|
1150
|
+
if (this.isRefSchema(schema)) {
|
|
1151
|
+
return;
|
|
1152
|
+
}
|
|
606
1153
|
const isArrayType = schema.properties[propertyName].type ===
|
|
607
1154
|
constants.jsPrimitives.Array.value;
|
|
608
1155
|
for (const decorator of decorators) {
|
|
@@ -718,8 +1265,193 @@ class SchemaTransformer {
|
|
|
718
1265
|
case constants.validatorDecorators.ArrayMaxSize.name:
|
|
719
1266
|
schema.properties[propertyName].maxItems = decorator.arguments[0];
|
|
720
1267
|
break;
|
|
1268
|
+
case constants.validatorDecorators.IsEnum.name:
|
|
1269
|
+
this.applyEnumDecorator(decorator, schema, propertyName, isArrayType);
|
|
1270
|
+
break;
|
|
1271
|
+
}
|
|
1272
|
+
}
|
|
1273
|
+
}
|
|
1274
|
+
/**
|
|
1275
|
+
* Applies the @IsEnum decorator to a property, handling both primitive values and object enums.
|
|
1276
|
+
* Supports arrays of enum values as well.
|
|
1277
|
+
*
|
|
1278
|
+
* @param decorator - The IsEnum decorator information
|
|
1279
|
+
* @param schema - The schema object to modify
|
|
1280
|
+
* @param propertyName - The name of the property
|
|
1281
|
+
* @param isArrayType - Whether the property is an array type
|
|
1282
|
+
* @private
|
|
1283
|
+
*/
|
|
1284
|
+
applyEnumDecorator(decorator, schema, propertyName, isArrayType) {
|
|
1285
|
+
if (!decorator.arguments || decorator.arguments.length === 0) {
|
|
1286
|
+
return;
|
|
1287
|
+
}
|
|
1288
|
+
const enumArg = decorator.arguments[0];
|
|
1289
|
+
let enumValues = [];
|
|
1290
|
+
// Handle different enum argument types
|
|
1291
|
+
if (typeof enumArg === 'string') {
|
|
1292
|
+
// This is likely a reference to an enum type name
|
|
1293
|
+
// We need to try to resolve this to actual enum values
|
|
1294
|
+
enumValues = this.resolveEnumValues(enumArg);
|
|
1295
|
+
}
|
|
1296
|
+
else if (typeof enumArg === 'object' && enumArg !== null) {
|
|
1297
|
+
// Object enum - extract values
|
|
1298
|
+
if (Array.isArray(enumArg)) {
|
|
1299
|
+
// Already an array of values
|
|
1300
|
+
enumValues = enumArg;
|
|
1301
|
+
}
|
|
1302
|
+
else {
|
|
1303
|
+
// Enum object - get all values
|
|
1304
|
+
enumValues = Object.values(enumArg);
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
// If we couldn't resolve enum values, fall back to string type without enum constraint
|
|
1308
|
+
if (enumValues.length === 0) {
|
|
1309
|
+
if (!isArrayType) {
|
|
1310
|
+
schema.properties[propertyName].type = 'string';
|
|
1311
|
+
}
|
|
1312
|
+
else if (schema.properties[propertyName].items) {
|
|
1313
|
+
schema.properties[propertyName].items.type = 'string';
|
|
1314
|
+
}
|
|
1315
|
+
return;
|
|
1316
|
+
}
|
|
1317
|
+
// Determine the type based on enum values
|
|
1318
|
+
let enumType = 'string';
|
|
1319
|
+
if (enumValues.length > 0) {
|
|
1320
|
+
const firstValue = enumValues[0];
|
|
1321
|
+
if (typeof firstValue === 'number') {
|
|
1322
|
+
enumType = 'number';
|
|
1323
|
+
}
|
|
1324
|
+
else if (typeof firstValue === 'boolean') {
|
|
1325
|
+
enumType = 'boolean';
|
|
1326
|
+
}
|
|
1327
|
+
}
|
|
1328
|
+
// Apply enum to schema
|
|
1329
|
+
if (!isArrayType) {
|
|
1330
|
+
schema.properties[propertyName].type = enumType;
|
|
1331
|
+
schema.properties[propertyName].enum = enumValues;
|
|
1332
|
+
}
|
|
1333
|
+
else if (schema.properties[propertyName].items) {
|
|
1334
|
+
schema.properties[propertyName].items.type = enumType;
|
|
1335
|
+
schema.properties[propertyName].items.enum = enumValues;
|
|
1336
|
+
}
|
|
1337
|
+
}
|
|
1338
|
+
/**
|
|
1339
|
+
* Attempts to resolve enum values from an enum type name.
|
|
1340
|
+
* This searches through the TypeScript AST to find the enum declaration
|
|
1341
|
+
* and extract its values.
|
|
1342
|
+
*
|
|
1343
|
+
* @param enumTypeName - The name of the enum type
|
|
1344
|
+
* @returns Array of enum values if found, empty array otherwise
|
|
1345
|
+
* @private
|
|
1346
|
+
*/
|
|
1347
|
+
resolveEnumValues(enumTypeName) {
|
|
1348
|
+
// Search for enum declarations in source files
|
|
1349
|
+
for (const sourceFile of this.program.getSourceFiles()) {
|
|
1350
|
+
if (sourceFile.isDeclarationFile)
|
|
1351
|
+
continue;
|
|
1352
|
+
if (sourceFile.fileName.includes('node_modules'))
|
|
1353
|
+
continue;
|
|
1354
|
+
const enumValues = this.findEnumValues(sourceFile, enumTypeName);
|
|
1355
|
+
if (enumValues.length > 0) {
|
|
1356
|
+
return enumValues;
|
|
1357
|
+
}
|
|
1358
|
+
}
|
|
1359
|
+
return [];
|
|
1360
|
+
}
|
|
1361
|
+
/**
|
|
1362
|
+
* Finds enum values in a specific source file.
|
|
1363
|
+
*
|
|
1364
|
+
* @param sourceFile - The source file to search
|
|
1365
|
+
* @param enumTypeName - The name of the enum to find
|
|
1366
|
+
* @returns Array of enum values if found, empty array otherwise
|
|
1367
|
+
* @private
|
|
1368
|
+
*/
|
|
1369
|
+
findEnumValues(sourceFile, enumTypeName) {
|
|
1370
|
+
let enumValues = [];
|
|
1371
|
+
const visit = (node) => {
|
|
1372
|
+
// Handle TypeScript enum declarations
|
|
1373
|
+
if (ts.isEnumDeclaration(node) && node.name?.text === enumTypeName) {
|
|
1374
|
+
enumValues = this.extractEnumValues(node);
|
|
1375
|
+
return;
|
|
1376
|
+
}
|
|
1377
|
+
// Handle const object declarations (like const Status = { ... } as const)
|
|
1378
|
+
if (ts.isVariableStatement(node)) {
|
|
1379
|
+
for (const declaration of node.declarationList.declarations) {
|
|
1380
|
+
if (ts.isVariableDeclaration(declaration) &&
|
|
1381
|
+
ts.isIdentifier(declaration.name) &&
|
|
1382
|
+
declaration.name.text === enumTypeName &&
|
|
1383
|
+
declaration.initializer) {
|
|
1384
|
+
let initializer = declaration.initializer;
|
|
1385
|
+
// Handle "as const" assertions
|
|
1386
|
+
if (ts.isAsExpression(initializer) && initializer.expression) {
|
|
1387
|
+
initializer = initializer.expression;
|
|
1388
|
+
}
|
|
1389
|
+
enumValues = this.extractObjectEnumValues(initializer);
|
|
1390
|
+
return;
|
|
1391
|
+
}
|
|
1392
|
+
}
|
|
1393
|
+
}
|
|
1394
|
+
ts.forEachChild(node, visit);
|
|
1395
|
+
};
|
|
1396
|
+
visit(sourceFile);
|
|
1397
|
+
return enumValues;
|
|
1398
|
+
}
|
|
1399
|
+
/**
|
|
1400
|
+
* Extracts values from a TypeScript enum declaration.
|
|
1401
|
+
*
|
|
1402
|
+
* @param enumNode - The enum declaration node
|
|
1403
|
+
* @returns Array of enum values
|
|
1404
|
+
* @private
|
|
1405
|
+
*/
|
|
1406
|
+
extractEnumValues(enumNode) {
|
|
1407
|
+
const values = [];
|
|
1408
|
+
for (const member of enumNode.members) {
|
|
1409
|
+
if (member.initializer) {
|
|
1410
|
+
// Handle initialized enum members
|
|
1411
|
+
if (ts.isStringLiteral(member.initializer)) {
|
|
1412
|
+
values.push(member.initializer.text);
|
|
1413
|
+
}
|
|
1414
|
+
else if (ts.isNumericLiteral(member.initializer)) {
|
|
1415
|
+
values.push(Number(member.initializer.text));
|
|
1416
|
+
}
|
|
1417
|
+
}
|
|
1418
|
+
else {
|
|
1419
|
+
// Handle auto-incremented numeric enums
|
|
1420
|
+
if (values.length === 0) {
|
|
1421
|
+
values.push(0);
|
|
1422
|
+
}
|
|
1423
|
+
else {
|
|
1424
|
+
const lastValue = values[values.length - 1];
|
|
1425
|
+
if (typeof lastValue === 'number') {
|
|
1426
|
+
values.push(lastValue + 1);
|
|
1427
|
+
}
|
|
1428
|
+
}
|
|
1429
|
+
}
|
|
1430
|
+
}
|
|
1431
|
+
return values;
|
|
1432
|
+
}
|
|
1433
|
+
/**
|
|
1434
|
+
* Extracts values from object literal enum (const object as const).
|
|
1435
|
+
*
|
|
1436
|
+
* @param initializer - The object literal initializer
|
|
1437
|
+
* @returns Array of enum values
|
|
1438
|
+
* @private
|
|
1439
|
+
*/
|
|
1440
|
+
extractObjectEnumValues(initializer) {
|
|
1441
|
+
const values = [];
|
|
1442
|
+
if (ts.isObjectLiteralExpression(initializer)) {
|
|
1443
|
+
for (const property of initializer.properties) {
|
|
1444
|
+
if (ts.isPropertyAssignment(property) && property.initializer) {
|
|
1445
|
+
if (ts.isStringLiteral(property.initializer)) {
|
|
1446
|
+
values.push(property.initializer.text);
|
|
1447
|
+
}
|
|
1448
|
+
else if (ts.isNumericLiteral(property.initializer)) {
|
|
1449
|
+
values.push(Number(property.initializer.text));
|
|
1450
|
+
}
|
|
1451
|
+
}
|
|
721
1452
|
}
|
|
722
1453
|
}
|
|
1454
|
+
return values;
|
|
723
1455
|
}
|
|
724
1456
|
/**
|
|
725
1457
|
* Applies sensible default behaviors for properties without class-validator decorators.
|
|
@@ -739,6 +1471,10 @@ class SchemaTransformer {
|
|
|
739
1471
|
* @private
|
|
740
1472
|
*/
|
|
741
1473
|
applyTypeBasedFormats(property, schema) {
|
|
1474
|
+
// Skip applying type-based formats to $ref schemas
|
|
1475
|
+
if (this.isRefSchema(schema)) {
|
|
1476
|
+
return;
|
|
1477
|
+
}
|
|
742
1478
|
const propertyName = property.name;
|
|
743
1479
|
const propertyType = property.type.toLowerCase();
|
|
744
1480
|
const propertySchema = schema.properties[propertyName];
|
|
@@ -773,6 +1509,10 @@ class SchemaTransformer {
|
|
|
773
1509
|
* @private
|
|
774
1510
|
*/
|
|
775
1511
|
determineRequiredStatus(property, schema) {
|
|
1512
|
+
// Skip determining required status for $ref schemas
|
|
1513
|
+
if (this.isRefSchema(schema)) {
|
|
1514
|
+
return;
|
|
1515
|
+
}
|
|
776
1516
|
const propertyName = property.name;
|
|
777
1517
|
// Check if already marked as required by IsNotEmpty or ArrayNotEmpty decorator
|
|
778
1518
|
const isAlreadyRequired = schema.required.includes(propertyName);
|
|
@@ -813,7 +1553,7 @@ class SchemaTransformer {
|
|
|
813
1553
|
* @public
|
|
814
1554
|
*/
|
|
815
1555
|
function transform(cls, options) {
|
|
816
|
-
return SchemaTransformer.
|
|
1556
|
+
return SchemaTransformer.transformClass(cls, options);
|
|
817
1557
|
}
|
|
818
1558
|
|
|
819
1559
|
class FileTest {
|
|
@@ -857,3 +1597,4 @@ try {
|
|
|
857
1597
|
catch (error) {
|
|
858
1598
|
console.error('❌ Error:', error instanceof Error ? error.message : String(error));
|
|
859
1599
|
}
|
|
1600
|
+
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicnVuLmpzIiwic291cmNlcyI6WyIuLi9zcmMvdHJhbnNmb3JtZXIuZml4dHVyZXMudHMiLCIuLi9zcmMvdHJhbnNmb3JtZXIudHMiLCIuLi9zcmMvcnVuLnRzIl0sInNvdXJjZXNDb250ZW50IjpbbnVsbCxudWxsLG51bGxdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQVdBLE1BQU0sc0JBQXNCLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsR0FBRyxFQUFFLEVBQUUsZUFBZSxDQUFDO0FBRTNFLE1BQU0sWUFBWSxHQUFHO0lBQ25CLE1BQU0sRUFBRSxFQUFFLElBQUksRUFBRSxRQUFRLEVBQUUsS0FBSyxFQUFFLFFBQVEsRUFBRTtBQUMzQyxJQUFBLE1BQU0sRUFBRSxFQUFFLElBQUksRUFBRSxRQUFRLEVBQUUsS0FBSyxFQUFFLFFBQVEsRUFBRSxNQUFNLEVBQUUsT0FBTyxFQUFFO0lBQzVELE9BQU8sRUFBRSxFQUFFLElBQUksRUFBRSxTQUFTLEVBQUUsS0FBSyxFQUFFLFNBQVMsRUFBRTtJQUM5QyxNQUFNLEVBQUUsRUFBRSxJQUFJLEVBQUUsUUFBUSxFQUFFLEtBQUssRUFBRSxRQUFRLEVBQUU7QUFDM0MsSUFBQSxNQUFNLEVBQUUsRUFBRSxJQUFJLEVBQUUsUUFBUSxFQUFFLEtBQUssRUFBRSxTQUFTLEVBQUUsTUFBTSxFQUFFLE9BQU8sRUFBRTtJQUM3RCxJQUFJLEVBQUUsRUFBRSxJQUFJLEVBQUUsTUFBTSxFQUFFLEtBQUssRUFBRSxNQUFNLEVBQUU7SUFDckMsTUFBTSxFQUFFLEVBQUUsSUFBSSxFQUFFLFFBQVEsRUFBRSxLQUFLLEVBQUUsUUFBUSxFQUFFO0lBQzNDLEtBQUssRUFBRSxFQUFFLElBQUksRUFBRSxPQUFPLEVBQUUsS0FBSyxFQUFFLE9BQU8sRUFBRTtBQUN4QyxJQUFBLElBQUksRUFBRSxFQUFFLElBQUksRUFBRSxNQUFNLEVBQUUsS0FBSyxFQUFFLFFBQVEsRUFBRSxNQUFNLEVBQUUsV0FBVyxFQUFFO0lBQzVELFFBQVEsRUFBRSxFQUFFLElBQUksRUFBRSxVQUFVLEVBQUUsS0FBSyxFQUFFLFVBQVUsRUFBRTtBQUNqRCxJQUFBLE1BQU0sRUFBRSxFQUFFLElBQUksRUFBRSxRQUFRLEVBQUUsS0FBSyxFQUFFLFFBQVEsRUFBRSxNQUFNLEVBQUUsUUFBUSxFQUFFO0FBQzdELElBQUEsVUFBVSxFQUFFLEVBQUUsSUFBSSxFQUFFLFlBQVksRUFBRSxLQUFLLEVBQUUsUUFBUSxFQUFFLE1BQU0sRUFBRSxRQUFRLEVBQUU7QUFDckUsSUFBQSxVQUFVLEVBQUUsRUFBRSxJQUFJLEVBQUUsWUFBWSxFQUFFLEtBQUssRUFBRSxRQUFRLEVBQUUsTUFBTSxFQUFFLFFBQVEsRUFBRTtBQUNyRSxJQUFBLElBQUksRUFBRSxFQUFFLElBQUksRUFBRSxNQUFNLEVBQUUsS0FBSyxFQUFFLFFBQVEsRUFBRSxNQUFNLEVBQUUsUUFBUSxFQUFFO0NBQzFEO0FBRUQsTUFBTSxtQkFBbUIsR0FBRztJQUMxQixNQUFNLEVBQUUsRUFBRSxJQUFJLEVBQUUsUUFBUSxFQUFFLElBQUksRUFBRSxRQUFRLEVBQUU7SUFDMUMsU0FBUyxFQUFFLEVBQUUsSUFBSSxFQUFFLFdBQVcsRUFBRSxJQUFJLEVBQUUsUUFBUSxFQUFFO0lBQ2hELFNBQVMsRUFBRSxFQUFFLElBQUksRUFBRSxXQUFXLEVBQUUsSUFBSSxFQUFFLFFBQVEsRUFBRTtBQUNoRCxJQUFBLEtBQUssRUFBRSxFQUFFLElBQUksRUFBRSxPQUFPLEVBQUUsSUFBSSxFQUFFLFNBQVMsRUFBRSxNQUFNLEVBQUUsT0FBTyxFQUFFO0FBQzFELElBQUEsUUFBUSxFQUFFLEVBQUUsSUFBSSxFQUFFLFVBQVUsRUFBRSxJQUFJLEVBQUUsUUFBUSxFQUFFLE1BQU0sRUFBRSxRQUFRLEVBQUU7QUFDaEUsSUFBQSxRQUFRLEVBQUUsRUFBRSxJQUFJLEVBQUUsVUFBVSxFQUFFLElBQUksRUFBRSxRQUFRLEVBQUUsTUFBTSxFQUFFLFFBQVEsRUFBRTtJQUNoRSxVQUFVLEVBQUUsRUFBRSxJQUFJLEVB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
|