ts-class-to-openapi 1.0.4 → 1.0.6
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 +369 -875
- package/dist/__test__/entities/additional-test-classes.d.ts +12 -0
- package/dist/__test__/entities/decorated-classes.d.ts +54 -0
- package/dist/__test__/entities/nested-classes.d.ts +70 -0
- package/dist/__test__/entities/pure-classes.d.ts +37 -0
- package/dist/__test__/entities/schema-validation-classes.d.ts +35 -0
- package/dist/__test__/index.d.ts +3 -6
- package/dist/__test__/test.d.ts +4 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.esm.js +476 -1075
- package/dist/index.js +476 -1075
- package/dist/run.d.ts +1 -1
- package/dist/run.js +1064 -1101
- package/dist/transformer.d.ts +1 -471
- package/dist/transformer.fixtures.d.ts +21 -0
- package/dist/types.d.ts +55 -6
- package/package.json +16 -15
- package/dist/__test__/entities/address.entity.d.ts +0 -5
- package/dist/__test__/entities/array.entity.d.ts +0 -7
- package/dist/__test__/entities/broken.entity.d.ts +0 -7
- package/dist/__test__/entities/complete.entity.d.ts +0 -16
- package/dist/__test__/entities/complex-generics.entity.d.ts +0 -33
- package/dist/__test__/entities/comprehensive-enum.entity.d.ts +0 -23
- package/dist/__test__/entities/enum.entity.d.ts +0 -29
- package/dist/__test__/entities/generic.entity.d.ts +0 -11
- package/dist/__test__/entities/optional-properties.entity.d.ts +0 -11
- package/dist/__test__/entities/plain.entity.d.ts +0 -19
- package/dist/__test__/entities/simple.entity.d.ts +0 -5
- package/dist/__test__/entities/upload.entity.d.ts +0 -8
- package/dist/__test__/entities/user-role-generic.entity.d.ts +0 -13
- package/dist/__test__/test-entities/duplicate-name.entity.d.ts +0 -5
- package/dist/__test__/test-entities/generic.entity.d.ts +0 -11
- /package/dist/__test__/{enum.test.d.ts → testCases/debug.test.d.ts} +0 -0
- /package/dist/__test__/{generic-types.test.d.ts → testCases/decorated-classes.test.d.ts} +0 -0
- /package/dist/__test__/{integration.test.d.ts → testCases/edge-cases.test.d.ts} +0 -0
- /package/dist/__test__/{main.test.d.ts → testCases/nested-classes.test.d.ts} +0 -0
- /package/dist/__test__/{optional-properties.test.d.ts → testCases/pure-classes.test.d.ts} +0 -0
- /package/dist/__test__/{plain.test.d.ts → testCases/schema-validation.test.d.ts} +0 -0
package/dist/run.js
CHANGED
|
@@ -1,112 +1,65 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var node_test = require('node:test');
|
|
4
|
+
var assert = require('node:assert');
|
|
3
5
|
var ts = require('typescript');
|
|
4
6
|
var path = require('path');
|
|
7
|
+
var classValidator = require('class-validator');
|
|
5
8
|
|
|
6
9
|
const TS_CONFIG_DEFAULT_PATH = path.resolve(process.cwd(), 'tsconfig.json');
|
|
7
10
|
const jsPrimitives = {
|
|
8
11
|
String: { type: 'String', value: 'string' },
|
|
9
|
-
|
|
12
|
+
Any: { type: 'Any'},
|
|
13
|
+
Unknown: { type: 'Unknown'},
|
|
14
|
+
Number: { type: 'Number', value: 'number', format: 'double' },
|
|
10
15
|
Boolean: { type: 'Boolean', value: 'boolean' },
|
|
11
|
-
Symbol: { type: 'Symbol', value: '
|
|
16
|
+
Symbol: { type: 'Symbol', value: 'string' },
|
|
12
17
|
BigInt: { type: 'BigInt', value: 'integer', format: 'int64' },
|
|
13
|
-
null: { type: 'null'
|
|
18
|
+
null: { type: 'null'},
|
|
14
19
|
Object: { type: 'Object', value: 'object' },
|
|
15
20
|
Array: { type: 'Array', value: 'array' },
|
|
16
21
|
Date: { type: 'Date', value: 'string', format: 'date-time' },
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
Uint8Array: { type: 'Uint8Array', value: 'string', format: 'binary' },
|
|
22
|
+
Buffer: { type: 'Buffer', value: 'string'},
|
|
23
|
+
Uint8Array: { type: 'Uint8Array', value: 'string'},
|
|
20
24
|
UploadFile: { type: 'UploadFile', value: 'string', format: 'binary' },
|
|
21
|
-
File: { type: 'File', value: 'string'
|
|
25
|
+
File: { type: 'File', value: 'string'},
|
|
22
26
|
};
|
|
23
27
|
const validatorDecorators = {
|
|
24
|
-
Length: { name: 'Length'
|
|
25
|
-
MinLength: { name: 'MinLength'
|
|
26
|
-
MaxLength: { name: 'MaxLength'
|
|
28
|
+
Length: { name: 'Length'},
|
|
29
|
+
MinLength: { name: 'MinLength'},
|
|
30
|
+
MaxLength: { name: 'MaxLength'},
|
|
27
31
|
IsInt: { name: 'IsInt', type: 'integer', format: 'int32' },
|
|
28
|
-
IsNumber: { name: 'IsNumber', type: 'number'
|
|
29
|
-
IsString: { name: 'IsString', type: 'string'
|
|
30
|
-
IsPositive: { name: 'IsPositive'
|
|
32
|
+
IsNumber: { name: 'IsNumber', type: 'number'},
|
|
33
|
+
IsString: { name: 'IsString', type: 'string'},
|
|
34
|
+
IsPositive: { name: 'IsPositive'},
|
|
31
35
|
IsDate: { name: 'IsDate', type: 'string', format: 'date-time' },
|
|
32
|
-
IsEmail: { name: 'IsEmail',
|
|
36
|
+
IsEmail: { name: 'IsEmail', format: 'email' },
|
|
33
37
|
IsNotEmpty: { name: 'IsNotEmpty' },
|
|
38
|
+
IsOptional: { name: 'IsOptional' },
|
|
34
39
|
IsBoolean: { name: 'IsBoolean', type: 'boolean' },
|
|
35
|
-
IsArray: { name: 'IsArray'
|
|
40
|
+
IsArray: { name: 'IsArray'},
|
|
36
41
|
Min: { name: 'Min' },
|
|
37
42
|
Max: { name: 'Max' },
|
|
38
43
|
ArrayNotEmpty: { name: 'ArrayNotEmpty' },
|
|
39
44
|
ArrayMaxSize: { name: 'ArrayMaxSize' },
|
|
40
45
|
ArrayMinSize: { name: 'ArrayMinSize' },
|
|
41
|
-
IsEnum: { name: 'IsEnum'
|
|
46
|
+
IsEnum: { name: 'IsEnum'},
|
|
42
47
|
};
|
|
43
48
|
const constants = {
|
|
44
49
|
TS_CONFIG_DEFAULT_PATH,
|
|
45
50
|
jsPrimitives,
|
|
46
|
-
validatorDecorators
|
|
47
|
-
};
|
|
51
|
+
validatorDecorators};
|
|
48
52
|
|
|
49
|
-
/**
|
|
50
|
-
* Transforms class-validator decorated classes into OpenAPI schema objects.
|
|
51
|
-
* Analyzes TypeScript source files directly using the TypeScript compiler API.
|
|
52
|
-
* Implemented as a singleton for performance optimization.
|
|
53
|
-
*
|
|
54
|
-
* @example
|
|
55
|
-
* ```typescript
|
|
56
|
-
* const transformer = SchemaTransformer.getInstance();
|
|
57
|
-
* const schema = transformer.transform(User);
|
|
58
|
-
* console.log(schema);
|
|
59
|
-
* ```
|
|
60
|
-
*
|
|
61
|
-
* @public
|
|
62
|
-
*/
|
|
63
53
|
class SchemaTransformer {
|
|
64
|
-
/**
|
|
65
|
-
* Singleton instance
|
|
66
|
-
* @private
|
|
67
|
-
*/
|
|
68
54
|
static instance = null;
|
|
69
|
-
/**
|
|
70
|
-
* TypeScript program instance for analyzing source files.
|
|
71
|
-
* @private
|
|
72
|
-
*/
|
|
73
55
|
program;
|
|
74
|
-
/**
|
|
75
|
-
* TypeScript type checker for resolving types.
|
|
76
|
-
* @private
|
|
77
|
-
*/
|
|
78
56
|
checker;
|
|
79
|
-
/**
|
|
80
|
-
* Cache for storing transformed class schemas to avoid reprocessing.
|
|
81
|
-
* Key format: "fileName:className" for uniqueness across different files.
|
|
82
|
-
* @private
|
|
83
|
-
*/
|
|
84
57
|
classCache = new Map();
|
|
85
|
-
/**
|
|
86
|
-
* Maximum number of entries to keep in cache before cleanup
|
|
87
|
-
* @private
|
|
88
|
-
*/
|
|
89
58
|
maxCacheSize;
|
|
90
|
-
/**
|
|
91
|
-
* Whether to automatically clean up cache
|
|
92
|
-
* @private
|
|
93
|
-
*/
|
|
94
59
|
autoCleanup;
|
|
95
|
-
/**
|
|
96
|
-
* Set of file paths that have been loaded to avoid redundant processing
|
|
97
|
-
* @private
|
|
98
|
-
*/
|
|
99
60
|
loadedFiles = new Set();
|
|
100
|
-
|
|
101
|
-
* Private constructor for singleton pattern.
|
|
102
|
-
*
|
|
103
|
-
* @param tsConfigPath - Optional path to a specific TypeScript config file
|
|
104
|
-
* @param options - Configuration options for memory management
|
|
105
|
-
* @throws {Error} When TypeScript configuration cannot be loaded
|
|
106
|
-
* @private
|
|
107
|
-
*/
|
|
61
|
+
processingClasses = new Set();
|
|
108
62
|
constructor(tsConfigPath = constants.TS_CONFIG_DEFAULT_PATH, options = {}) {
|
|
109
|
-
// Initialize configuration with defaults
|
|
110
63
|
this.maxCacheSize = options.maxCacheSize ?? 100;
|
|
111
64
|
this.autoCleanup = options.autoCleanup ?? true;
|
|
112
65
|
const { config, error } = ts.readConfigFile(tsConfigPath || 'tsconfig.json', ts.sys.readFile);
|
|
@@ -118,282 +71,7 @@ class SchemaTransformer {
|
|
|
118
71
|
this.program = ts.createProgram(fileNames, tsOptions);
|
|
119
72
|
this.checker = this.program.getTypeChecker();
|
|
120
73
|
}
|
|
121
|
-
|
|
122
|
-
* Generates a unique cache key using file name and class name.
|
|
123
|
-
*
|
|
124
|
-
* @param fileName - The source file name
|
|
125
|
-
* @param className - The class name
|
|
126
|
-
* @returns Unique cache key in format "fileName:className"
|
|
127
|
-
* @private
|
|
128
|
-
*/
|
|
129
|
-
getCacheKey(fileName, className) {
|
|
130
|
-
return `${fileName}:${className}`;
|
|
131
|
-
}
|
|
132
|
-
/**
|
|
133
|
-
* Cleans up cache when it exceeds maximum size to prevent memory leaks.
|
|
134
|
-
* Removes oldest entries using LRU strategy.
|
|
135
|
-
* @private
|
|
136
|
-
*/
|
|
137
|
-
cleanupCache() {
|
|
138
|
-
if (!this.autoCleanup || this.classCache.size <= this.maxCacheSize) {
|
|
139
|
-
return;
|
|
140
|
-
}
|
|
141
|
-
const entries = Array.from(this.classCache.entries());
|
|
142
|
-
const toDelete = entries.slice(0, Math.floor(this.maxCacheSize / 2));
|
|
143
|
-
for (const [key] of toDelete) {
|
|
144
|
-
this.classCache.delete(key);
|
|
145
|
-
}
|
|
146
|
-
// Force garbage collection hint
|
|
147
|
-
if (global.gc) {
|
|
148
|
-
global.gc();
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
/**
|
|
152
|
-
* Gets relevant source files for a class, filtering out unnecessary files to save memory.
|
|
153
|
-
*
|
|
154
|
-
* @param className - The name of the class to find files for
|
|
155
|
-
* @param filePath - Optional specific file path
|
|
156
|
-
* @returns Array of relevant source files
|
|
157
|
-
* @private
|
|
158
|
-
*/
|
|
159
|
-
getRelevantSourceFiles(className, filePath) {
|
|
160
|
-
if (filePath) {
|
|
161
|
-
const sourceFile = this.program.getSourceFile(filePath);
|
|
162
|
-
return sourceFile ? [sourceFile] : [];
|
|
163
|
-
}
|
|
164
|
-
// Only get source files that are not declaration files and not in node_modules
|
|
165
|
-
return this.program.getSourceFiles().filter(sf => {
|
|
166
|
-
if (sf.isDeclarationFile)
|
|
167
|
-
return false;
|
|
168
|
-
if (sf.fileName.includes('.d.ts'))
|
|
169
|
-
return false;
|
|
170
|
-
if (sf.fileName.includes('node_modules'))
|
|
171
|
-
return false;
|
|
172
|
-
// Mark file as loaded for memory tracking
|
|
173
|
-
this.loadedFiles.add(sf.fileName);
|
|
174
|
-
return true;
|
|
175
|
-
});
|
|
176
|
-
}
|
|
177
|
-
/**
|
|
178
|
-
* Transforms a class by its name into an OpenAPI schema object.
|
|
179
|
-
* Now considers the context of the calling file to resolve ambiguous class names.
|
|
180
|
-
*
|
|
181
|
-
* @param className - The name of the class to transform
|
|
182
|
-
* @param filePath - Optional path to the file containing the class
|
|
183
|
-
* @param contextFile - Optional context file for resolving class ambiguity
|
|
184
|
-
* @returns Object containing the class name and its corresponding JSON schema
|
|
185
|
-
* @throws {Error} When the specified class cannot be found
|
|
186
|
-
* @private
|
|
187
|
-
*/
|
|
188
|
-
transformByName(className, filePath, contextFile) {
|
|
189
|
-
const sourceFiles = this.getRelevantSourceFiles(className, filePath);
|
|
190
|
-
// If we have a context file, try to find the class in that file first
|
|
191
|
-
if (contextFile) {
|
|
192
|
-
const contextSourceFile = this.program.getSourceFile(contextFile);
|
|
193
|
-
if (contextSourceFile) {
|
|
194
|
-
const classNode = this.findClassByName(contextSourceFile, className);
|
|
195
|
-
if (classNode) {
|
|
196
|
-
const cacheKey = this.getCacheKey(contextSourceFile.fileName, className);
|
|
197
|
-
// Check cache first
|
|
198
|
-
if (this.classCache.has(cacheKey)) {
|
|
199
|
-
return this.classCache.get(cacheKey);
|
|
200
|
-
}
|
|
201
|
-
const result = this.transformClass(classNode, contextSourceFile);
|
|
202
|
-
this.classCache.set(cacheKey, result);
|
|
203
|
-
this.cleanupCache();
|
|
204
|
-
return result;
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
// Fallback to searching all files, but prioritize files that are more likely to be relevant
|
|
209
|
-
const prioritizedFiles = this.prioritizeSourceFiles(sourceFiles, contextFile);
|
|
210
|
-
for (const sourceFile of prioritizedFiles) {
|
|
211
|
-
const classNode = this.findClassByName(sourceFile, className);
|
|
212
|
-
if (classNode && sourceFile?.fileName) {
|
|
213
|
-
const cacheKey = this.getCacheKey(sourceFile.fileName, className);
|
|
214
|
-
// Check cache first using fileName:className as key
|
|
215
|
-
if (this.classCache.has(cacheKey)) {
|
|
216
|
-
return this.classCache.get(cacheKey);
|
|
217
|
-
}
|
|
218
|
-
const result = this.transformClass(classNode, sourceFile);
|
|
219
|
-
// Cache using fileName:className as key for uniqueness
|
|
220
|
-
this.classCache.set(cacheKey, result);
|
|
221
|
-
// Clean up cache if it gets too large
|
|
222
|
-
this.cleanupCache();
|
|
223
|
-
return result;
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
throw new Error(`Class ${className} not found`);
|
|
227
|
-
}
|
|
228
|
-
/**
|
|
229
|
-
* Prioritizes source files based on context to resolve class name conflicts.
|
|
230
|
-
* Gives priority to files in the same directory or with similar names.
|
|
231
|
-
*
|
|
232
|
-
* @param sourceFiles - Array of source files to prioritize
|
|
233
|
-
* @param contextFile - Optional context file for prioritization
|
|
234
|
-
* @returns Prioritized array of source files
|
|
235
|
-
* @private
|
|
236
|
-
*/
|
|
237
|
-
prioritizeSourceFiles(sourceFiles, contextFile) {
|
|
238
|
-
if (!contextFile) {
|
|
239
|
-
return sourceFiles;
|
|
240
|
-
}
|
|
241
|
-
const contextDir = contextFile.substring(0, contextFile.lastIndexOf('/'));
|
|
242
|
-
return sourceFiles.sort((a, b) => {
|
|
243
|
-
const aDir = a.fileName.substring(0, a.fileName.lastIndexOf('/'));
|
|
244
|
-
const bDir = b.fileName.substring(0, b.fileName.lastIndexOf('/'));
|
|
245
|
-
// Prioritize files in the same directory as context
|
|
246
|
-
const aInSameDir = aDir === contextDir ? 1 : 0;
|
|
247
|
-
const bInSameDir = bDir === contextDir ? 1 : 0;
|
|
248
|
-
if (aInSameDir !== bInSameDir) {
|
|
249
|
-
return bInSameDir - aInSameDir; // Higher priority first
|
|
250
|
-
}
|
|
251
|
-
// Prioritize non-test files over test files
|
|
252
|
-
const aIsTest = a.fileName.includes('test') || a.fileName.includes('spec') ? 0 : 1;
|
|
253
|
-
const bIsTest = b.fileName.includes('test') || b.fileName.includes('spec') ? 0 : 1;
|
|
254
|
-
if (aIsTest !== bIsTest) {
|
|
255
|
-
return bIsTest - aIsTest; // Non-test files first
|
|
256
|
-
}
|
|
257
|
-
return 0;
|
|
258
|
-
});
|
|
259
|
-
}
|
|
260
|
-
/**
|
|
261
|
-
* Gets the singleton instance of SchemaTransformer.
|
|
262
|
-
*
|
|
263
|
-
* @param tsConfigPath - Optional path to a specific TypeScript config file (only used on first call)
|
|
264
|
-
* @param options - Configuration options for memory management (only used on first call)
|
|
265
|
-
* @returns The singleton instance
|
|
266
|
-
*
|
|
267
|
-
* @example
|
|
268
|
-
* ```typescript
|
|
269
|
-
* const transformer = SchemaTransformer.getInstance();
|
|
270
|
-
* ```
|
|
271
|
-
*
|
|
272
|
-
* @example
|
|
273
|
-
* ```typescript
|
|
274
|
-
* // With memory optimization options
|
|
275
|
-
* const transformer = SchemaTransformer.getInstance('./tsconfig.json', {
|
|
276
|
-
* maxCacheSize: 50,
|
|
277
|
-
* autoCleanup: true
|
|
278
|
-
* });
|
|
279
|
-
* ```
|
|
280
|
-
*
|
|
281
|
-
* @public
|
|
282
|
-
*/
|
|
283
|
-
/**
|
|
284
|
-
* Clears the current singleton instance. Useful for testing or when you need
|
|
285
|
-
* to create a new instance with different configuration.
|
|
286
|
-
*/
|
|
287
|
-
static clearInstance() {
|
|
288
|
-
SchemaTransformer.instance = null;
|
|
289
|
-
}
|
|
290
|
-
static getInstance(tsConfigPath, options) {
|
|
291
|
-
if (!SchemaTransformer.instance) {
|
|
292
|
-
SchemaTransformer.instance = new SchemaTransformer(tsConfigPath, options);
|
|
293
|
-
}
|
|
294
|
-
return SchemaTransformer.instance;
|
|
295
|
-
}
|
|
296
|
-
/**
|
|
297
|
-
* Transforms a class constructor function into an OpenAPI schema object.
|
|
298
|
-
*
|
|
299
|
-
* @param cls - The class constructor function to transform
|
|
300
|
-
* @returns Object containing the class name and its corresponding JSON schema
|
|
301
|
-
*
|
|
302
|
-
* @example
|
|
303
|
-
* ```typescript
|
|
304
|
-
* import { User } from './entities/user.js';
|
|
305
|
-
* const transformer = SchemaTransformer.getInstance();
|
|
306
|
-
* const schema = transformer.transform(User);
|
|
307
|
-
* ```
|
|
308
|
-
*
|
|
309
|
-
* @public
|
|
310
|
-
*/
|
|
311
|
-
transform(cls) {
|
|
312
|
-
return this.transformByName(cls.name);
|
|
313
|
-
}
|
|
314
|
-
/**
|
|
315
|
-
* Clears all cached schemas and loaded file references to free memory.
|
|
316
|
-
* Useful for long-running applications or when processing many different classes.
|
|
317
|
-
*
|
|
318
|
-
* @example
|
|
319
|
-
* ```typescript
|
|
320
|
-
* const transformer = SchemaTransformer.getInstance();
|
|
321
|
-
* // After processing many classes...
|
|
322
|
-
* transformer.clearCache();
|
|
323
|
-
* ```
|
|
324
|
-
*
|
|
325
|
-
* @public
|
|
326
|
-
*/
|
|
327
|
-
clearCache() {
|
|
328
|
-
this.classCache.clear();
|
|
329
|
-
this.loadedFiles.clear();
|
|
330
|
-
// Force garbage collection hint if available
|
|
331
|
-
if (global.gc) {
|
|
332
|
-
global.gc();
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
/**
|
|
336
|
-
* Gets memory usage statistics for monitoring and debugging.
|
|
337
|
-
*
|
|
338
|
-
* @returns Object containing cache size and loaded files count
|
|
339
|
-
*
|
|
340
|
-
* @example
|
|
341
|
-
* ```typescript
|
|
342
|
-
* const transformer = SchemaTransformer.getInstance();
|
|
343
|
-
* const stats = transformer.getMemoryStats();
|
|
344
|
-
* console.log(`Cache entries: ${stats.cacheSize}, Files loaded: ${stats.loadedFiles}`);
|
|
345
|
-
* ```
|
|
346
|
-
*
|
|
347
|
-
* @public
|
|
348
|
-
*/
|
|
349
|
-
getMemoryStats() {
|
|
350
|
-
return {
|
|
351
|
-
cacheSize: this.classCache.size,
|
|
352
|
-
loadedFiles: this.loadedFiles.size,
|
|
353
|
-
};
|
|
354
|
-
}
|
|
355
|
-
/**
|
|
356
|
-
* Finds a class declaration by name within a source file.
|
|
357
|
-
*
|
|
358
|
-
* @param sourceFile - The TypeScript source file to search in
|
|
359
|
-
* @param className - The name of the class to find
|
|
360
|
-
* @returns The class declaration node if found, undefined otherwise
|
|
361
|
-
* @private
|
|
362
|
-
*/
|
|
363
|
-
findClassByName(sourceFile, className) {
|
|
364
|
-
let result;
|
|
365
|
-
const visit = (node) => {
|
|
366
|
-
if (ts.isClassDeclaration(node) && node.name?.text === className) {
|
|
367
|
-
result = node;
|
|
368
|
-
return;
|
|
369
|
-
}
|
|
370
|
-
ts.forEachChild(node, visit);
|
|
371
|
-
};
|
|
372
|
-
visit(sourceFile);
|
|
373
|
-
return result;
|
|
374
|
-
}
|
|
375
|
-
/**
|
|
376
|
-
* Transforms a TypeScript class declaration into a schema object.
|
|
377
|
-
*
|
|
378
|
-
* @param classNode - The TypeScript class declaration node
|
|
379
|
-
* @param sourceFile - The source file containing the class (for context)
|
|
380
|
-
* @returns Object containing class name and generated schema
|
|
381
|
-
* @private
|
|
382
|
-
*/
|
|
383
|
-
transformClass(classNode, sourceFile) {
|
|
384
|
-
const className = classNode.name?.text || 'Unknown';
|
|
385
|
-
const properties = this.extractProperties(classNode);
|
|
386
|
-
const schema = this.generateSchema(properties, sourceFile?.fileName);
|
|
387
|
-
return { name: className, schema };
|
|
388
|
-
}
|
|
389
|
-
/**
|
|
390
|
-
* Extracts property information from a class declaration.
|
|
391
|
-
*
|
|
392
|
-
* @param classNode - The TypeScript class declaration node
|
|
393
|
-
* @returns Array of property information including names, types, decorators, and optional status
|
|
394
|
-
* @private
|
|
395
|
-
*/
|
|
396
|
-
extractProperties(classNode) {
|
|
74
|
+
getPropertiesByClassDeclaration(classNode) {
|
|
397
75
|
const properties = [];
|
|
398
76
|
for (const member of classNode.members) {
|
|
399
77
|
if (ts.isPropertyDeclaration(member) &&
|
|
@@ -403,272 +81,35 @@ class SchemaTransformer {
|
|
|
403
81
|
const type = this.getPropertyType(member);
|
|
404
82
|
const decorators = this.extractDecorators(member);
|
|
405
83
|
const isOptional = !!member.questionToken;
|
|
406
|
-
|
|
84
|
+
const isGeneric = this.isPropertyTypeGeneric(member);
|
|
85
|
+
const isPrimitive = this.isPrimitiveType(type);
|
|
86
|
+
const property = {
|
|
407
87
|
name: propertyName,
|
|
408
88
|
type,
|
|
409
89
|
decorators,
|
|
410
90
|
isOptional,
|
|
411
|
-
|
|
91
|
+
isGeneric,
|
|
92
|
+
originalProperty: member,
|
|
93
|
+
isPrimitive,
|
|
94
|
+
isClassType: this.isClassType(member),
|
|
95
|
+
isArray: this.isArrayProperty(member),
|
|
96
|
+
};
|
|
97
|
+
properties.push(property);
|
|
412
98
|
}
|
|
413
99
|
}
|
|
414
100
|
return properties;
|
|
415
101
|
}
|
|
416
|
-
/**
|
|
417
|
-
* Gets the TypeScript type of a property as a string.
|
|
418
|
-
*
|
|
419
|
-
* @param property - The property declaration to analyze
|
|
420
|
-
* @returns String representation of the property's type
|
|
421
|
-
* @private
|
|
422
|
-
*/
|
|
423
102
|
getPropertyType(property) {
|
|
424
103
|
if (property.type) {
|
|
425
104
|
return this.getTypeNodeToString(property.type);
|
|
426
105
|
}
|
|
427
106
|
const type = this.checker.getTypeAtLocation(property);
|
|
428
|
-
return this.
|
|
429
|
-
}
|
|
430
|
-
/**
|
|
431
|
-
* Resolves generic types by analyzing the type alias and its arguments.
|
|
432
|
-
* For example, User<Role> where User is a type alias will be resolved to its structure.
|
|
433
|
-
*
|
|
434
|
-
* @param typeNode - The TypeScript type reference node with generic arguments
|
|
435
|
-
* @returns String representation of the resolved type or schema
|
|
436
|
-
* @private
|
|
437
|
-
*/
|
|
438
|
-
resolveGenericType(typeNode) {
|
|
439
|
-
const typeName = typeNode.typeName.text;
|
|
440
|
-
const typeArguments = typeNode.typeArguments;
|
|
441
|
-
if (!typeArguments || typeArguments.length === 0) {
|
|
442
|
-
return typeName;
|
|
443
|
-
}
|
|
444
|
-
// Try to resolve the type using the TypeScript type checker
|
|
445
|
-
const type = this.checker.getTypeAtLocation(typeNode);
|
|
446
|
-
const resolvedType = this.checker.typeToString(type);
|
|
447
|
-
// If we can resolve it to a meaningful structure, use that
|
|
448
|
-
if (resolvedType &&
|
|
449
|
-
resolvedType !== typeName &&
|
|
450
|
-
!resolvedType.includes('any')) {
|
|
451
|
-
// For type aliases like User<Role>, we want to create a synthetic type name
|
|
452
|
-
// that represents the resolved structure
|
|
453
|
-
const typeArgNames = typeArguments.map(arg => {
|
|
454
|
-
if (ts.isTypeReferenceNode(arg) && ts.isIdentifier(arg.typeName)) {
|
|
455
|
-
return arg.typeName.text;
|
|
456
|
-
}
|
|
457
|
-
return this.getTypeNodeToString(arg);
|
|
458
|
-
});
|
|
459
|
-
return `${typeName}_${typeArgNames.join('_')}`;
|
|
460
|
-
}
|
|
461
|
-
return typeName;
|
|
462
|
-
}
|
|
463
|
-
/**
|
|
464
|
-
* Checks if a type string represents a resolved generic type.
|
|
465
|
-
*
|
|
466
|
-
* @param type - The type string to check
|
|
467
|
-
* @returns True if it's a resolved generic type
|
|
468
|
-
* @private
|
|
469
|
-
*/
|
|
470
|
-
isResolvedGenericType(type) {
|
|
471
|
-
// Simple heuristic: resolved generic types contain underscores and
|
|
472
|
-
// the parts after underscore should be known types
|
|
473
|
-
const parts = type.split('_');
|
|
474
|
-
return (parts.length > 1 &&
|
|
475
|
-
parts
|
|
476
|
-
.slice(1)
|
|
477
|
-
.every(part => this.isKnownType(part) || this.isPrimitiveType(part)));
|
|
478
|
-
}
|
|
479
|
-
/**
|
|
480
|
-
* Checks if a type is a known class or interface.
|
|
481
|
-
*
|
|
482
|
-
* @param typeName - The type name to check
|
|
483
|
-
* @returns True if it's a known type
|
|
484
|
-
* @private
|
|
485
|
-
*/
|
|
486
|
-
isKnownType(typeName) {
|
|
487
|
-
// First check if it's a primitive type to avoid unnecessary lookups
|
|
488
|
-
if (this.isPrimitiveType(typeName)) {
|
|
489
|
-
return true;
|
|
490
|
-
}
|
|
491
|
-
try {
|
|
492
|
-
// Use a more conservative approach - check if we can find the class
|
|
493
|
-
// without actually transforming it to avoid side effects
|
|
494
|
-
const found = this.findClassInProject(typeName);
|
|
495
|
-
return found !== null;
|
|
496
|
-
}
|
|
497
|
-
catch {
|
|
498
|
-
return false;
|
|
499
|
-
}
|
|
500
|
-
}
|
|
501
|
-
/**
|
|
502
|
-
* Finds a class by name in the project without transforming it.
|
|
503
|
-
*
|
|
504
|
-
* @param className - The class name to find
|
|
505
|
-
* @returns True if found, false otherwise
|
|
506
|
-
* @private
|
|
507
|
-
*/
|
|
508
|
-
findClassInProject(className) {
|
|
509
|
-
const sourceFiles = this.program.getSourceFiles().filter(sf => {
|
|
510
|
-
if (sf.isDeclarationFile)
|
|
511
|
-
return false;
|
|
512
|
-
if (sf.fileName.includes('.d.ts'))
|
|
513
|
-
return false;
|
|
514
|
-
if (sf.fileName.includes('node_modules'))
|
|
515
|
-
return false;
|
|
516
|
-
return true;
|
|
517
|
-
});
|
|
518
|
-
for (const sourceFile of sourceFiles) {
|
|
519
|
-
const found = this.findClassByName(sourceFile, className);
|
|
520
|
-
if (found)
|
|
521
|
-
return true;
|
|
522
|
-
}
|
|
523
|
-
return false;
|
|
524
|
-
}
|
|
525
|
-
/**
|
|
526
|
-
* Checks if a type is a primitive type.
|
|
527
|
-
*
|
|
528
|
-
* @param typeName - The type name to check
|
|
529
|
-
* @returns True if it's a primitive type
|
|
530
|
-
* @private
|
|
531
|
-
*/
|
|
532
|
-
isPrimitiveType(typeName) {
|
|
533
|
-
const lowerTypeName = typeName.toLowerCase();
|
|
534
|
-
// Check against all primitive types from constants
|
|
535
|
-
const primitiveTypes = [
|
|
536
|
-
constants.jsPrimitives.String.type.toLowerCase(),
|
|
537
|
-
constants.jsPrimitives.Number.type.toLowerCase(),
|
|
538
|
-
constants.jsPrimitives.Boolean.type.toLowerCase(),
|
|
539
|
-
constants.jsPrimitives.Date.type.toLowerCase(),
|
|
540
|
-
constants.jsPrimitives.Buffer.type.toLowerCase(),
|
|
541
|
-
constants.jsPrimitives.Uint8Array.type.toLowerCase(),
|
|
542
|
-
constants.jsPrimitives.File.type.toLowerCase(),
|
|
543
|
-
constants.jsPrimitives.UploadFile.type.toLowerCase(),
|
|
544
|
-
constants.jsPrimitives.BigInt.type.toLowerCase(),
|
|
545
|
-
];
|
|
546
|
-
return primitiveTypes.includes(lowerTypeName);
|
|
547
|
-
}
|
|
548
|
-
/**
|
|
549
|
-
* Resolves a generic type schema by analyzing the type alias structure.
|
|
550
|
-
*
|
|
551
|
-
* @param resolvedTypeName - The resolved generic type name (e.g., User_Role)
|
|
552
|
-
* @returns OpenAPI schema for the resolved generic type
|
|
553
|
-
* @private
|
|
554
|
-
*/
|
|
555
|
-
resolveGenericTypeSchema(resolvedTypeName) {
|
|
556
|
-
const parts = resolvedTypeName.split('_');
|
|
557
|
-
const baseTypeName = parts[0];
|
|
558
|
-
const typeArgNames = parts.slice(1);
|
|
559
|
-
if (!baseTypeName) {
|
|
560
|
-
return null;
|
|
561
|
-
}
|
|
562
|
-
// Find the original type alias declaration
|
|
563
|
-
const typeAliasSymbol = this.findTypeAliasDeclaration(baseTypeName);
|
|
564
|
-
if (!typeAliasSymbol) {
|
|
565
|
-
return null;
|
|
566
|
-
}
|
|
567
|
-
// Create a schema based on the type alias structure, substituting type parameters
|
|
568
|
-
return this.createSchemaFromTypeAlias(typeAliasSymbol, typeArgNames);
|
|
569
|
-
}
|
|
570
|
-
/**
|
|
571
|
-
* Finds a type alias declaration by name.
|
|
572
|
-
*
|
|
573
|
-
* @param typeName - The type alias name to find
|
|
574
|
-
* @returns The type alias declaration node or null
|
|
575
|
-
* @private
|
|
576
|
-
*/
|
|
577
|
-
findTypeAliasDeclaration(typeName) {
|
|
578
|
-
for (const sourceFile of this.program.getSourceFiles()) {
|
|
579
|
-
if (sourceFile.isDeclarationFile)
|
|
580
|
-
continue;
|
|
581
|
-
const findTypeAlias = (node) => {
|
|
582
|
-
if (ts.isTypeAliasDeclaration(node) && node.name.text === typeName) {
|
|
583
|
-
return node;
|
|
584
|
-
}
|
|
585
|
-
return ts.forEachChild(node, findTypeAlias) || null;
|
|
586
|
-
};
|
|
587
|
-
const result = findTypeAlias(sourceFile);
|
|
588
|
-
if (result)
|
|
589
|
-
return result;
|
|
590
|
-
}
|
|
591
|
-
return null;
|
|
592
|
-
}
|
|
593
|
-
/**
|
|
594
|
-
* Creates a schema from a type alias declaration, substituting type parameters.
|
|
595
|
-
*
|
|
596
|
-
* @param typeAlias - The type alias declaration
|
|
597
|
-
* @param typeArgNames - The concrete type arguments
|
|
598
|
-
* @returns OpenAPI schema for the type alias
|
|
599
|
-
* @private
|
|
600
|
-
*/
|
|
601
|
-
createSchemaFromTypeAlias(typeAlias, typeArgNames) {
|
|
602
|
-
const typeNode = typeAlias.type;
|
|
603
|
-
if (ts.isTypeLiteralNode(typeNode)) {
|
|
604
|
-
const schema = {
|
|
605
|
-
type: 'object',
|
|
606
|
-
properties: {},
|
|
607
|
-
required: [],
|
|
608
|
-
};
|
|
609
|
-
for (const member of typeNode.members) {
|
|
610
|
-
if (ts.isPropertySignature(member) &&
|
|
611
|
-
member.name &&
|
|
612
|
-
ts.isIdentifier(member.name)) {
|
|
613
|
-
const propertyName = member.name.text;
|
|
614
|
-
const isOptional = !!member.questionToken;
|
|
615
|
-
if (member.type) {
|
|
616
|
-
const propertyType = this.resolveTypeParameterInTypeAlias(member.type, typeAlias.typeParameters, typeArgNames);
|
|
617
|
-
const { type, format, nestedSchema } = this.mapTypeToSchema(propertyType);
|
|
618
|
-
if (nestedSchema) {
|
|
619
|
-
schema.properties[propertyName] = nestedSchema;
|
|
620
|
-
}
|
|
621
|
-
else {
|
|
622
|
-
schema.properties[propertyName] = { type };
|
|
623
|
-
if (format)
|
|
624
|
-
schema.properties[propertyName].format = format;
|
|
625
|
-
}
|
|
626
|
-
if (!isOptional) {
|
|
627
|
-
schema.required.push(propertyName);
|
|
628
|
-
}
|
|
629
|
-
}
|
|
630
|
-
}
|
|
631
|
-
}
|
|
632
|
-
return schema;
|
|
633
|
-
}
|
|
634
|
-
return null;
|
|
107
|
+
return this.getStringFromType(type);
|
|
635
108
|
}
|
|
636
|
-
/**
|
|
637
|
-
* Resolves type parameters in a type alias to concrete types.
|
|
638
|
-
*
|
|
639
|
-
* @param typeNode - The type node to resolve
|
|
640
|
-
* @param typeParameters - The type parameters of the type alias
|
|
641
|
-
* @param typeArgNames - The concrete type arguments
|
|
642
|
-
* @returns The resolved type string
|
|
643
|
-
* @private
|
|
644
|
-
*/
|
|
645
|
-
resolveTypeParameterInTypeAlias(typeNode, typeParameters, typeArgNames) {
|
|
646
|
-
if (ts.isTypeReferenceNode(typeNode) &&
|
|
647
|
-
ts.isIdentifier(typeNode.typeName)) {
|
|
648
|
-
const typeName = typeNode.typeName.text;
|
|
649
|
-
// Check if this is a type parameter
|
|
650
|
-
if (typeParameters) {
|
|
651
|
-
const paramIndex = typeParameters.findIndex(param => param.name.text === typeName);
|
|
652
|
-
if (paramIndex !== -1 && paramIndex < typeArgNames.length) {
|
|
653
|
-
const resolvedType = typeArgNames[paramIndex];
|
|
654
|
-
return resolvedType || typeName;
|
|
655
|
-
}
|
|
656
|
-
}
|
|
657
|
-
return typeName;
|
|
658
|
-
}
|
|
659
|
-
return this.getTypeNodeToString(typeNode);
|
|
660
|
-
}
|
|
661
|
-
/**
|
|
662
|
-
* Converts a TypeScript type node to its string representation.
|
|
663
|
-
*
|
|
664
|
-
* @param typeNode - The TypeScript type node to convert
|
|
665
|
-
* @returns String representation of the type
|
|
666
|
-
* @private
|
|
667
|
-
*/
|
|
668
109
|
getTypeNodeToString(typeNode) {
|
|
669
110
|
if (ts.isTypeReferenceNode(typeNode) &&
|
|
670
111
|
ts.isIdentifier(typeNode.typeName)) {
|
|
671
|
-
if (typeNode.typeName.text.toLowerCase()
|
|
112
|
+
if (typeNode.typeName.text.toLowerCase() === 'uploadfile') {
|
|
672
113
|
return 'UploadFile';
|
|
673
114
|
}
|
|
674
115
|
if (typeNode.typeArguments && typeNode.typeArguments.length > 0) {
|
|
@@ -676,12 +117,9 @@ class SchemaTransformer {
|
|
|
676
117
|
if (firstTypeArg &&
|
|
677
118
|
ts.isTypeReferenceNode(firstTypeArg) &&
|
|
678
119
|
ts.isIdentifier(firstTypeArg.typeName)) {
|
|
679
|
-
if (firstTypeArg.typeName.text.toLowerCase()
|
|
120
|
+
if (firstTypeArg.typeName.text.toLowerCase() === 'uploadfile') {
|
|
680
121
|
return 'UploadFile';
|
|
681
122
|
}
|
|
682
|
-
if (typeNode.typeName.text === 'BaseDto') {
|
|
683
|
-
return firstTypeArg.typeName.text;
|
|
684
|
-
}
|
|
685
123
|
}
|
|
686
124
|
return this.resolveGenericType(typeNode);
|
|
687
125
|
}
|
|
@@ -720,13 +158,24 @@ class SchemaTransformer {
|
|
|
720
158
|
return typeText;
|
|
721
159
|
}
|
|
722
160
|
}
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
161
|
+
resolveGenericType(typeNode) {
|
|
162
|
+
const typeName = typeNode.typeName.text;
|
|
163
|
+
const typeArguments = typeNode.typeArguments;
|
|
164
|
+
if (!typeArguments || typeArguments.length === 0) {
|
|
165
|
+
return typeName;
|
|
166
|
+
}
|
|
167
|
+
const type = this.checker.getTypeAtLocation(typeNode);
|
|
168
|
+
const resolvedType = this.getStringFromType(type);
|
|
169
|
+
if (resolvedType &&
|
|
170
|
+
resolvedType !== typeName &&
|
|
171
|
+
!resolvedType.includes('any')) {
|
|
172
|
+
return resolvedType;
|
|
173
|
+
}
|
|
174
|
+
return typeName;
|
|
175
|
+
}
|
|
176
|
+
getStringFromType(type) {
|
|
177
|
+
return this.checker.typeToString(type);
|
|
178
|
+
}
|
|
730
179
|
extractDecorators(member) {
|
|
731
180
|
const decorators = [];
|
|
732
181
|
if (member.modifiers) {
|
|
@@ -745,26 +194,12 @@ class SchemaTransformer {
|
|
|
745
194
|
}
|
|
746
195
|
return decorators;
|
|
747
196
|
}
|
|
748
|
-
/**
|
|
749
|
-
* Gets the name of a decorator from a call expression.
|
|
750
|
-
*
|
|
751
|
-
* @param callExpression - The decorator call expression
|
|
752
|
-
* @returns The decorator name or "unknown" if not identifiable
|
|
753
|
-
* @private
|
|
754
|
-
*/
|
|
755
197
|
getDecoratorName(callExpression) {
|
|
756
198
|
if (ts.isIdentifier(callExpression.expression)) {
|
|
757
199
|
return callExpression.expression.text;
|
|
758
200
|
}
|
|
759
201
|
return 'unknown';
|
|
760
202
|
}
|
|
761
|
-
/**
|
|
762
|
-
* Extracts arguments from a decorator call expression.
|
|
763
|
-
*
|
|
764
|
-
* @param callExpression - The decorator call expression
|
|
765
|
-
* @returns Array of parsed decorator arguments
|
|
766
|
-
* @private
|
|
767
|
-
*/
|
|
768
203
|
getDecoratorArguments(callExpression) {
|
|
769
204
|
return callExpression.arguments.map(arg => {
|
|
770
205
|
if (ts.isNumericLiteral(arg))
|
|
@@ -778,572 +213,1100 @@ class SchemaTransformer {
|
|
|
778
213
|
return arg.getText();
|
|
779
214
|
});
|
|
780
215
|
}
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
216
|
+
isPropertyTypeGeneric(property) {
|
|
217
|
+
if (property.type && this.isGenericTypeFromNode(property.type)) {
|
|
218
|
+
return true;
|
|
219
|
+
}
|
|
220
|
+
try {
|
|
221
|
+
const type = this.checker.getTypeAtLocation(property);
|
|
222
|
+
return this.isGenericTypeFromSymbol(type);
|
|
223
|
+
}
|
|
224
|
+
catch (error) {
|
|
225
|
+
console.warn('Error analyzing property type for generics:', error);
|
|
226
|
+
return false;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
isGenericTypeFromNode(typeNode) {
|
|
230
|
+
if (ts.isTypeReferenceNode(typeNode) && typeNode.typeArguments) {
|
|
231
|
+
return typeNode.typeArguments.length > 0;
|
|
232
|
+
}
|
|
233
|
+
// Check for mapped types (e.g., { [K in keyof T]: T[K] })
|
|
234
|
+
if (ts.isMappedTypeNode(typeNode)) {
|
|
235
|
+
return true;
|
|
236
|
+
}
|
|
237
|
+
// Check for conditional types (e.g., T extends U ? X : Y)
|
|
238
|
+
if (ts.isConditionalTypeNode(typeNode)) {
|
|
239
|
+
return true;
|
|
240
|
+
}
|
|
241
|
+
// Check for indexed access types (e.g., T[K])
|
|
242
|
+
if (ts.isIndexedAccessTypeNode(typeNode)) {
|
|
243
|
+
return true;
|
|
244
|
+
}
|
|
245
|
+
// Check for type operators like keyof, typeof
|
|
246
|
+
if (ts.isTypeOperatorNode(typeNode)) {
|
|
247
|
+
return true;
|
|
248
|
+
}
|
|
249
|
+
return false;
|
|
250
|
+
}
|
|
251
|
+
isGenericTypeFromSymbol(type) {
|
|
252
|
+
// First check if it's a simple array type - these should NOT be considered generic
|
|
253
|
+
if (this.isSimpleArrayType(type)) {
|
|
254
|
+
return false;
|
|
255
|
+
}
|
|
256
|
+
// Check if the type has type parameters
|
|
257
|
+
if (type.aliasTypeArguments && type.aliasTypeArguments.length > 0) {
|
|
258
|
+
return true;
|
|
259
|
+
}
|
|
260
|
+
// Check if it's a type reference with type arguments
|
|
261
|
+
// But exclude simple arrays which internally use Array<T> representation
|
|
262
|
+
if (type.typeArguments && type.typeArguments.length > 0) {
|
|
263
|
+
const symbol = type.getSymbol();
|
|
264
|
+
if (symbol && symbol.getName() === 'Array') {
|
|
265
|
+
// This is Array<T> - only consider it generic if T itself is a utility type
|
|
266
|
+
const elementType = type.typeArguments[0];
|
|
267
|
+
if (elementType) {
|
|
268
|
+
return this.isUtilityTypeFromType(elementType);
|
|
269
|
+
}
|
|
270
|
+
return false;
|
|
799
271
|
}
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
272
|
+
const elementType = type.typeArguments[0];
|
|
273
|
+
return this.isUtilityTypeFromType(elementType);
|
|
274
|
+
}
|
|
275
|
+
// Check type flags for generic indicators
|
|
276
|
+
if (type.flags & ts.TypeFlags.TypeParameter) {
|
|
277
|
+
return true;
|
|
278
|
+
}
|
|
279
|
+
if (type.flags & ts.TypeFlags.Conditional) {
|
|
280
|
+
return true;
|
|
281
|
+
}
|
|
282
|
+
if (type.flags & ts.TypeFlags.Index) {
|
|
283
|
+
return true;
|
|
284
|
+
}
|
|
285
|
+
if (type.flags & ts.TypeFlags.IndexedAccess) {
|
|
286
|
+
return true;
|
|
287
|
+
}
|
|
288
|
+
// Check if the type symbol indicates a generic type
|
|
289
|
+
const symbol = type.getSymbol();
|
|
290
|
+
if (symbol && symbol.declarations) {
|
|
291
|
+
for (const declaration of symbol.declarations) {
|
|
292
|
+
// Check for type alias declarations with type parameters
|
|
293
|
+
if (ts.isTypeAliasDeclaration(declaration) &&
|
|
294
|
+
declaration.typeParameters) {
|
|
295
|
+
return true;
|
|
296
|
+
}
|
|
297
|
+
// Check for interface declarations with type parameters
|
|
298
|
+
if (ts.isInterfaceDeclaration(declaration) &&
|
|
299
|
+
declaration.typeParameters) {
|
|
300
|
+
return true;
|
|
301
|
+
}
|
|
302
|
+
// Check for class declarations with type parameters
|
|
303
|
+
if (ts.isClassDeclaration(declaration) && declaration.typeParameters) {
|
|
304
|
+
return true;
|
|
305
|
+
}
|
|
804
306
|
}
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
307
|
+
}
|
|
308
|
+
return false;
|
|
309
|
+
}
|
|
310
|
+
isUtilityTypeFromType(type) {
|
|
311
|
+
if (!type.aliasSymbol)
|
|
312
|
+
return false;
|
|
313
|
+
const aliasName = type.aliasSymbol.getName();
|
|
314
|
+
const utilityTypes = [
|
|
315
|
+
'Partial',
|
|
316
|
+
'Required',
|
|
317
|
+
'Readonly',
|
|
318
|
+
'Pick',
|
|
319
|
+
'Omit',
|
|
320
|
+
'Record',
|
|
321
|
+
'Exclude',
|
|
322
|
+
'Extract',
|
|
323
|
+
'NonNullable',
|
|
324
|
+
];
|
|
325
|
+
return utilityTypes.includes(aliasName);
|
|
326
|
+
}
|
|
327
|
+
isSimpleArrayType(type) {
|
|
328
|
+
const symbol = type.getSymbol();
|
|
329
|
+
if (!symbol || symbol.getName() !== 'Array') {
|
|
330
|
+
return false;
|
|
331
|
+
}
|
|
332
|
+
// Check if this is Array<T> where T is a simple, non-generic type
|
|
333
|
+
if (type.typeArguments &&
|
|
334
|
+
type.typeArguments.length === 1) {
|
|
335
|
+
const elementType = type.typeArguments[0];
|
|
336
|
+
if (!elementType)
|
|
337
|
+
return false;
|
|
338
|
+
// If the element type is a utility type, then this array should be considered generic
|
|
339
|
+
if (this.isUtilityTypeFromType(elementType)) {
|
|
340
|
+
return false;
|
|
810
341
|
}
|
|
811
|
-
//
|
|
812
|
-
|
|
342
|
+
// If the element type itself has generic parameters, this array is generic
|
|
343
|
+
if (elementType.typeArguments &&
|
|
344
|
+
elementType.typeArguments.length > 0) {
|
|
345
|
+
return false;
|
|
346
|
+
}
|
|
347
|
+
return true;
|
|
813
348
|
}
|
|
349
|
+
return false;
|
|
350
|
+
}
|
|
351
|
+
isPrimitiveType(typeName) {
|
|
352
|
+
const lowerTypeName = typeName.toLowerCase();
|
|
353
|
+
// Check against all primitive types from constants
|
|
354
|
+
const primitiveTypes = [
|
|
355
|
+
constants.jsPrimitives.String.type.toLowerCase(),
|
|
356
|
+
constants.jsPrimitives.Number.type.toLowerCase(),
|
|
357
|
+
constants.jsPrimitives.Boolean.type.toLowerCase(),
|
|
358
|
+
constants.jsPrimitives.Date.type.toLowerCase(),
|
|
359
|
+
constants.jsPrimitives.Buffer.type.toLowerCase(),
|
|
360
|
+
constants.jsPrimitives.Uint8Array.type.toLowerCase(),
|
|
361
|
+
constants.jsPrimitives.File.type.toLowerCase(),
|
|
362
|
+
constants.jsPrimitives.UploadFile.type.toLowerCase(),
|
|
363
|
+
constants.jsPrimitives.BigInt.type.toLowerCase(),
|
|
364
|
+
constants.jsPrimitives.Symbol.type.toLowerCase(),
|
|
365
|
+
constants.jsPrimitives.null.type.toLowerCase(),
|
|
366
|
+
constants.jsPrimitives.Object.type.toLowerCase(),
|
|
367
|
+
constants.jsPrimitives.Array.type.toLowerCase(),
|
|
368
|
+
constants.jsPrimitives.Any.type.toLowerCase(),
|
|
369
|
+
constants.jsPrimitives.Unknown.type.toLowerCase(),
|
|
370
|
+
];
|
|
371
|
+
const primitivesArray = primitiveTypes.map(t => t.concat('[]'));
|
|
372
|
+
return (primitiveTypes.includes(lowerTypeName) ||
|
|
373
|
+
primitivesArray.includes(lowerTypeName));
|
|
374
|
+
}
|
|
375
|
+
static getInstance(tsConfigPath, options) {
|
|
376
|
+
if (!SchemaTransformer.instance) {
|
|
377
|
+
SchemaTransformer.instance = new SchemaTransformer(tsConfigPath, options);
|
|
378
|
+
}
|
|
379
|
+
return SchemaTransformer.instance;
|
|
380
|
+
}
|
|
381
|
+
getSourceFileByClassName(className, sourceOptions) {
|
|
382
|
+
let sourceFiles = [];
|
|
383
|
+
if (sourceOptions?.isExternal) {
|
|
384
|
+
sourceFiles = this.program.getSourceFiles().filter(sf => {
|
|
385
|
+
return (sf.fileName.includes(sourceOptions.packageName) &&
|
|
386
|
+
(!sourceOptions.filePath || sf.fileName === sourceOptions.filePath));
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
else {
|
|
390
|
+
sourceFiles = this.program.getSourceFiles().filter(sf => {
|
|
391
|
+
if (sf.isDeclarationFile)
|
|
392
|
+
return false;
|
|
393
|
+
if (sf.fileName.includes('.d.ts'))
|
|
394
|
+
return false;
|
|
395
|
+
if (sf.fileName.includes('node_modules'))
|
|
396
|
+
return false;
|
|
397
|
+
return true;
|
|
398
|
+
});
|
|
399
|
+
}
|
|
400
|
+
for (const sourceFile of sourceFiles) {
|
|
401
|
+
let node;
|
|
402
|
+
const found = sourceFile.statements.some(stmt => {
|
|
403
|
+
node = stmt;
|
|
404
|
+
return (ts.isClassDeclaration(stmt) &&
|
|
405
|
+
stmt.name &&
|
|
406
|
+
stmt.name.text === className);
|
|
407
|
+
});
|
|
408
|
+
if (found) {
|
|
409
|
+
return { sourceFile, node: node };
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
isClassType(propertyDeclaration) {
|
|
414
|
+
// If there's no explicit type annotation, we can't determine reliably
|
|
415
|
+
if (!propertyDeclaration.type) {
|
|
416
|
+
return false;
|
|
417
|
+
}
|
|
418
|
+
// Check if the original property type is an array type
|
|
419
|
+
if (this.isArrayProperty(propertyDeclaration) &&
|
|
420
|
+
ts.isTypeReferenceNode(propertyDeclaration.type
|
|
421
|
+
.elementType)) {
|
|
422
|
+
const type = this.checker.getTypeAtLocation(propertyDeclaration.type.elementType);
|
|
423
|
+
const symbol = type.getSymbol();
|
|
424
|
+
if (symbol && symbol.declarations) {
|
|
425
|
+
return symbol.declarations.some(decl => ts.isClassDeclaration(decl));
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
else if (ts.isTypeReferenceNode(propertyDeclaration.type)) {
|
|
429
|
+
const type = this.checker.getTypeAtLocation(propertyDeclaration.type);
|
|
430
|
+
const symbol = type.getSymbol();
|
|
431
|
+
if (symbol && symbol.declarations) {
|
|
432
|
+
return symbol.declarations.some(decl => ts.isClassDeclaration(decl));
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
return false;
|
|
436
|
+
}
|
|
437
|
+
getDeclarationProperty(property) {
|
|
438
|
+
if (!property.originalProperty.type) {
|
|
439
|
+
return undefined;
|
|
440
|
+
}
|
|
441
|
+
if (ts.isArrayTypeNode(property.originalProperty.type) &&
|
|
442
|
+
ts.isTypeReferenceNode(property.originalProperty.type.elementType)) {
|
|
443
|
+
const type = this.checker.getTypeAtLocation(property.originalProperty.type.elementType);
|
|
444
|
+
const symbol = type.getSymbol();
|
|
445
|
+
if (symbol && symbol.declarations) {
|
|
446
|
+
return symbol.declarations[0];
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
else if (ts.isTypeReferenceNode(property.originalProperty.type)) {
|
|
450
|
+
const type = this.checker.getTypeAtLocation(property.originalProperty.type);
|
|
451
|
+
const symbol = type.getSymbol();
|
|
452
|
+
if (symbol && symbol.declarations) {
|
|
453
|
+
return symbol.declarations[0];
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
return undefined;
|
|
457
|
+
}
|
|
458
|
+
isArrayProperty(propertyDeclaration) {
|
|
459
|
+
if (!propertyDeclaration.type) {
|
|
460
|
+
return false;
|
|
461
|
+
}
|
|
462
|
+
return ts.isArrayTypeNode(propertyDeclaration.type);
|
|
463
|
+
}
|
|
464
|
+
getSchemaFromProperties({ properties, visitedClass, transformedSchema, }) {
|
|
465
|
+
let schema = {};
|
|
466
|
+
const required = [];
|
|
467
|
+
for (const property of properties) {
|
|
468
|
+
schema[property.name] = this.getSchemaFromProperty({
|
|
469
|
+
property,
|
|
470
|
+
visitedClass,
|
|
471
|
+
transformedSchema,
|
|
472
|
+
});
|
|
473
|
+
// this.applyDecorators(property, schema as SchemaType)
|
|
474
|
+
if (!property.isOptional) {
|
|
475
|
+
required.push(property.name);
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
return {
|
|
479
|
+
type: 'object',
|
|
480
|
+
properties: schema,
|
|
481
|
+
required: required.length ? required : undefined,
|
|
482
|
+
};
|
|
483
|
+
}
|
|
484
|
+
getSchemaFromProperty({ property, visitedClass, transformedSchema, }) {
|
|
485
|
+
let schema = {};
|
|
486
|
+
if (property.isPrimitive) {
|
|
487
|
+
schema = this.getSchemaFromPrimitive(property);
|
|
488
|
+
}
|
|
489
|
+
else if (property.isClassType) {
|
|
490
|
+
schema = this.getSchemaFromClass({
|
|
491
|
+
property,
|
|
492
|
+
visitedClass,
|
|
493
|
+
transformedSchema,
|
|
494
|
+
});
|
|
495
|
+
}
|
|
496
|
+
else {
|
|
497
|
+
schema = { type: 'object', properties: {}, additionalProperties: true };
|
|
498
|
+
}
|
|
499
|
+
this.applyDecorators(property, schema);
|
|
814
500
|
return schema;
|
|
815
501
|
}
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
const elementType = type.slice(0, -2);
|
|
829
|
-
const elementSchema = this.mapTypeToSchema(elementType, contextFile);
|
|
830
|
-
const items = elementSchema.nestedSchema || {
|
|
831
|
-
type: elementSchema.type,
|
|
832
|
-
};
|
|
833
|
-
if (elementSchema.format)
|
|
834
|
-
items.format = elementSchema.format;
|
|
502
|
+
getSchemaFromClass({ property, transformedSchema = new Map(), visitedClass = new Set(), }) {
|
|
503
|
+
let schema = { type: 'object' };
|
|
504
|
+
const declaration = this.getDeclarationProperty(property);
|
|
505
|
+
if (!declaration ||
|
|
506
|
+
!ts.isClassDeclaration(declaration) ||
|
|
507
|
+
!declaration.name) {
|
|
508
|
+
return { type: 'object' };
|
|
509
|
+
}
|
|
510
|
+
if (visitedClass.has(declaration)) {
|
|
511
|
+
if (transformedSchema.has(declaration.name.text)) {
|
|
512
|
+
return transformedSchema.get(declaration.name.text);
|
|
513
|
+
}
|
|
835
514
|
return {
|
|
836
|
-
|
|
837
|
-
nestedSchema: {
|
|
838
|
-
type: 'array',
|
|
839
|
-
items,
|
|
840
|
-
properties: {},
|
|
841
|
-
required: [],
|
|
842
|
-
},
|
|
515
|
+
$ref: `#/components/schemas/${declaration.name.text}`,
|
|
843
516
|
};
|
|
844
517
|
}
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
518
|
+
visitedClass.add(declaration);
|
|
519
|
+
const properties = this.getPropertiesByClassDeclaration(declaration);
|
|
520
|
+
let transformerProps = this.getSchemaFromProperties({
|
|
521
|
+
properties,
|
|
522
|
+
visitedClass,
|
|
523
|
+
transformedSchema: transformedSchema,
|
|
524
|
+
});
|
|
525
|
+
if (property.isArray) {
|
|
526
|
+
schema.type = 'array';
|
|
527
|
+
schema.items = {
|
|
528
|
+
type: transformerProps.type,
|
|
529
|
+
properties: transformerProps.properties,
|
|
530
|
+
required: transformerProps.required,
|
|
531
|
+
};
|
|
532
|
+
}
|
|
533
|
+
else {
|
|
534
|
+
schema.type = transformerProps.type;
|
|
535
|
+
schema.properties = transformerProps.properties;
|
|
536
|
+
schema.required = transformerProps.required;
|
|
537
|
+
}
|
|
538
|
+
transformedSchema.set(declaration.name.text, schema);
|
|
539
|
+
if (schema.properties && Object.keys(schema.properties).length === 0) {
|
|
540
|
+
schema = { type: 'object', properties: {}, additionalProperties: true };
|
|
541
|
+
}
|
|
542
|
+
return schema;
|
|
543
|
+
}
|
|
544
|
+
getSchemaFromPrimitive(property) {
|
|
545
|
+
const propertySchema = { type: 'object' };
|
|
546
|
+
const propertyType = property.type.toLowerCase().replace('[]', '').trim();
|
|
547
|
+
switch (propertyType) {
|
|
548
|
+
case constants.jsPrimitives.String.value:
|
|
549
|
+
propertySchema.type = constants.jsPrimitives.String.value;
|
|
550
|
+
break;
|
|
551
|
+
case constants.jsPrimitives.Number.value:
|
|
552
|
+
propertySchema.type = constants.jsPrimitives.Number.value;
|
|
553
|
+
propertySchema.format = constants.jsPrimitives.Number.format;
|
|
554
|
+
break;
|
|
555
|
+
case constants.jsPrimitives.BigInt.type.toLocaleLowerCase():
|
|
556
|
+
propertySchema.type = constants.jsPrimitives.BigInt.value;
|
|
557
|
+
propertySchema.format = constants.jsPrimitives.BigInt.format;
|
|
558
|
+
break;
|
|
559
|
+
case constants.jsPrimitives.Date.type.toLocaleLowerCase():
|
|
560
|
+
propertySchema.type = constants.jsPrimitives.Date.value;
|
|
561
|
+
propertySchema.format = constants.jsPrimitives.Date.format;
|
|
562
|
+
break;
|
|
563
|
+
case constants.jsPrimitives.Buffer.value:
|
|
564
|
+
case constants.jsPrimitives.Uint8Array.value:
|
|
565
|
+
case constants.jsPrimitives.File.value:
|
|
566
|
+
case constants.jsPrimitives.UploadFile.value:
|
|
567
|
+
propertySchema.type = constants.jsPrimitives.UploadFile.value;
|
|
568
|
+
propertySchema.format = constants.jsPrimitives.UploadFile.format;
|
|
569
|
+
break;
|
|
570
|
+
case constants.jsPrimitives.Array.value:
|
|
571
|
+
propertySchema.type = constants.jsPrimitives.Array.value;
|
|
572
|
+
break;
|
|
573
|
+
case constants.jsPrimitives.Boolean.value:
|
|
574
|
+
propertySchema.type = constants.jsPrimitives.Boolean.value;
|
|
575
|
+
break;
|
|
576
|
+
case constants.jsPrimitives.Symbol.type.toLocaleLowerCase():
|
|
577
|
+
propertySchema.type = constants.jsPrimitives.Symbol.value;
|
|
578
|
+
break;
|
|
579
|
+
case constants.jsPrimitives.Object.value:
|
|
580
|
+
propertySchema.type = constants.jsPrimitives.Object.value;
|
|
581
|
+
break;
|
|
872
582
|
default:
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
return {
|
|
879
|
-
type: constants.jsPrimitives.Object.value,
|
|
880
|
-
nestedSchema: genericSchema,
|
|
881
|
-
};
|
|
882
|
-
}
|
|
883
|
-
}
|
|
884
|
-
catch (error) {
|
|
885
|
-
console.warn(`Failed to resolve generic type ${type}:`, error);
|
|
886
|
-
}
|
|
887
|
-
}
|
|
888
|
-
// Handle nested objects
|
|
889
|
-
try {
|
|
890
|
-
const nestedResult = this.transformByName(type, undefined, contextFile);
|
|
891
|
-
return {
|
|
892
|
-
type: constants.jsPrimitives.Object.value,
|
|
893
|
-
nestedSchema: nestedResult.schema,
|
|
894
|
-
};
|
|
895
|
-
}
|
|
896
|
-
catch {
|
|
897
|
-
return { type: constants.jsPrimitives.Object.value };
|
|
898
|
-
}
|
|
583
|
+
propertySchema.type = constants.jsPrimitives.String.value;
|
|
584
|
+
}
|
|
585
|
+
if (property.isArray) {
|
|
586
|
+
propertySchema.type = `array`;
|
|
587
|
+
propertySchema.items = { type: propertyType };
|
|
899
588
|
}
|
|
589
|
+
return propertySchema;
|
|
900
590
|
}
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
* @param decorators - Array of decorator information to apply
|
|
906
|
-
* @param schema - The schema object to modify
|
|
907
|
-
* @param propertyName - Name of the property being processed
|
|
908
|
-
* @private
|
|
909
|
-
*/
|
|
910
|
-
applyDecorators(decorators, schema, propertyName) {
|
|
911
|
-
const isArrayType = schema.properties[propertyName].type ===
|
|
912
|
-
constants.jsPrimitives.Array.value;
|
|
913
|
-
for (const decorator of decorators) {
|
|
591
|
+
//Todo: implement properly
|
|
592
|
+
applyEnumDecorator(decorator, schema) { }
|
|
593
|
+
applyDecorators(property, schema) {
|
|
594
|
+
for (const decorator of property.decorators) {
|
|
914
595
|
const decoratorName = decorator.name;
|
|
915
596
|
switch (decoratorName) {
|
|
916
597
|
case constants.validatorDecorators.IsString.name:
|
|
917
|
-
if (!
|
|
918
|
-
schema.
|
|
919
|
-
constants.validatorDecorators.IsString.type;
|
|
598
|
+
if (!property.isArray) {
|
|
599
|
+
schema.type = constants.validatorDecorators.IsString.type;
|
|
920
600
|
}
|
|
921
|
-
else if (schema.
|
|
922
|
-
schema.
|
|
923
|
-
constants.validatorDecorators.IsString.type;
|
|
601
|
+
else if (schema.items) {
|
|
602
|
+
schema.items.type = constants.validatorDecorators.IsString.type;
|
|
924
603
|
}
|
|
925
604
|
break;
|
|
926
605
|
case constants.validatorDecorators.IsInt.name:
|
|
927
|
-
if (!
|
|
928
|
-
schema.
|
|
929
|
-
|
|
930
|
-
schema.properties[propertyName].format =
|
|
931
|
-
constants.validatorDecorators.IsInt.format;
|
|
606
|
+
if (!property.isArray) {
|
|
607
|
+
schema.type = constants.validatorDecorators.IsInt.type;
|
|
608
|
+
schema.format = constants.validatorDecorators.IsInt.format;
|
|
932
609
|
}
|
|
933
|
-
else if (schema.
|
|
934
|
-
schema.
|
|
935
|
-
|
|
936
|
-
schema.properties[propertyName].items.format =
|
|
937
|
-
constants.validatorDecorators.IsInt.format;
|
|
610
|
+
else if (schema.items) {
|
|
611
|
+
schema.items.type = constants.validatorDecorators.IsInt.type;
|
|
612
|
+
schema.items.format = constants.validatorDecorators.IsInt.format;
|
|
938
613
|
}
|
|
939
614
|
break;
|
|
940
615
|
case constants.validatorDecorators.IsNumber.name:
|
|
941
|
-
if (!
|
|
942
|
-
schema.
|
|
943
|
-
constants.validatorDecorators.IsNumber.type;
|
|
616
|
+
if (!property.isArray) {
|
|
617
|
+
schema.type = constants.validatorDecorators.IsNumber.type;
|
|
944
618
|
}
|
|
945
|
-
else if (schema.
|
|
946
|
-
schema.
|
|
947
|
-
constants.validatorDecorators.IsNumber.type;
|
|
619
|
+
else if (schema.items) {
|
|
620
|
+
schema.items.type = constants.validatorDecorators.IsNumber.type;
|
|
948
621
|
}
|
|
949
622
|
break;
|
|
950
623
|
case constants.validatorDecorators.IsBoolean.name:
|
|
951
|
-
if (!
|
|
952
|
-
schema.
|
|
953
|
-
constants.validatorDecorators.IsBoolean.type;
|
|
624
|
+
if (!property.isArray) {
|
|
625
|
+
schema.type = constants.validatorDecorators.IsBoolean.type;
|
|
954
626
|
}
|
|
955
|
-
else if (schema.
|
|
956
|
-
schema.
|
|
957
|
-
constants.validatorDecorators.IsBoolean.type;
|
|
627
|
+
else if (schema.items) {
|
|
628
|
+
schema.items.type = constants.validatorDecorators.IsBoolean.type;
|
|
958
629
|
}
|
|
959
630
|
break;
|
|
960
631
|
case constants.validatorDecorators.IsEmail.name:
|
|
961
|
-
if (!
|
|
962
|
-
schema.
|
|
963
|
-
constants.validatorDecorators.IsEmail.format;
|
|
632
|
+
if (!property.isArray) {
|
|
633
|
+
schema.format = constants.validatorDecorators.IsEmail.format;
|
|
964
634
|
}
|
|
965
|
-
else if (schema.
|
|
966
|
-
schema.
|
|
967
|
-
constants.validatorDecorators.IsEmail.format;
|
|
635
|
+
else if (schema.items) {
|
|
636
|
+
schema.items.format = constants.validatorDecorators.IsEmail.format;
|
|
968
637
|
}
|
|
969
638
|
break;
|
|
970
639
|
case constants.validatorDecorators.IsDate.name:
|
|
971
|
-
if (!
|
|
972
|
-
schema.
|
|
973
|
-
|
|
974
|
-
schema.properties[propertyName].format =
|
|
975
|
-
constants.validatorDecorators.IsDate.format;
|
|
640
|
+
if (!property.isArray) {
|
|
641
|
+
schema.type = constants.validatorDecorators.IsDate.type;
|
|
642
|
+
schema.format = constants.validatorDecorators.IsDate.format;
|
|
976
643
|
}
|
|
977
|
-
else if (schema.
|
|
978
|
-
schema.
|
|
979
|
-
|
|
980
|
-
schema.properties[propertyName].items.format =
|
|
981
|
-
constants.validatorDecorators.IsDate.format;
|
|
644
|
+
else if (schema.items) {
|
|
645
|
+
schema.items.type = constants.validatorDecorators.IsDate.type;
|
|
646
|
+
schema.items.format = constants.validatorDecorators.IsDate.format;
|
|
982
647
|
}
|
|
983
648
|
break;
|
|
984
649
|
case constants.validatorDecorators.IsNotEmpty.name:
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
650
|
+
property.isOptional = false;
|
|
651
|
+
break;
|
|
652
|
+
case constants.validatorDecorators.IsOptional.name:
|
|
653
|
+
property.isOptional = true;
|
|
988
654
|
break;
|
|
989
655
|
case constants.validatorDecorators.MinLength.name:
|
|
990
|
-
schema.
|
|
656
|
+
schema.minLength = decorator.arguments[0];
|
|
991
657
|
break;
|
|
992
658
|
case constants.validatorDecorators.MaxLength.name:
|
|
993
|
-
schema.
|
|
659
|
+
schema.maxLength = decorator.arguments[0];
|
|
994
660
|
break;
|
|
995
661
|
case constants.validatorDecorators.Length.name:
|
|
996
|
-
schema.
|
|
662
|
+
schema.minLength = decorator.arguments[0];
|
|
997
663
|
if (decorator.arguments[1]) {
|
|
998
|
-
schema.
|
|
664
|
+
schema.maxLength = decorator.arguments[1];
|
|
999
665
|
}
|
|
1000
666
|
break;
|
|
1001
667
|
case constants.validatorDecorators.Min.name:
|
|
1002
|
-
schema.
|
|
668
|
+
schema.minimum = decorator.arguments[0];
|
|
1003
669
|
break;
|
|
1004
670
|
case constants.validatorDecorators.Max.name:
|
|
1005
|
-
schema.
|
|
671
|
+
schema.maximum = decorator.arguments[0];
|
|
1006
672
|
break;
|
|
1007
673
|
case constants.validatorDecorators.IsPositive.name:
|
|
1008
|
-
schema.
|
|
674
|
+
schema.minimum = 0;
|
|
1009
675
|
break;
|
|
1010
676
|
case constants.validatorDecorators.IsArray.name:
|
|
1011
|
-
schema.
|
|
1012
|
-
constants.jsPrimitives.Array.value;
|
|
677
|
+
schema.type = constants.jsPrimitives.Array.value;
|
|
1013
678
|
break;
|
|
1014
679
|
case constants.validatorDecorators.ArrayNotEmpty.name:
|
|
1015
|
-
schema.
|
|
1016
|
-
|
|
1017
|
-
schema.required.push(propertyName);
|
|
1018
|
-
}
|
|
680
|
+
schema.minItems = 1;
|
|
681
|
+
property.isOptional = false;
|
|
1019
682
|
break;
|
|
1020
683
|
case constants.validatorDecorators.ArrayMinSize.name:
|
|
1021
|
-
schema.
|
|
684
|
+
schema.minItems = decorator.arguments[0];
|
|
1022
685
|
break;
|
|
1023
686
|
case constants.validatorDecorators.ArrayMaxSize.name:
|
|
1024
|
-
schema.
|
|
687
|
+
schema.maxItems = decorator.arguments[0];
|
|
1025
688
|
break;
|
|
1026
689
|
case constants.validatorDecorators.IsEnum.name:
|
|
1027
|
-
this.applyEnumDecorator(decorator, schema
|
|
690
|
+
this.applyEnumDecorator(decorator, schema);
|
|
1028
691
|
break;
|
|
1029
692
|
}
|
|
1030
693
|
}
|
|
1031
694
|
}
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
* @param propertyName - The name of the property
|
|
1039
|
-
* @param isArrayType - Whether the property is an array type
|
|
1040
|
-
* @private
|
|
1041
|
-
*/
|
|
1042
|
-
applyEnumDecorator(decorator, schema, propertyName, isArrayType) {
|
|
1043
|
-
if (!decorator.arguments || decorator.arguments.length === 0) {
|
|
1044
|
-
return;
|
|
1045
|
-
}
|
|
1046
|
-
const enumArg = decorator.arguments[0];
|
|
1047
|
-
let enumValues = [];
|
|
1048
|
-
// Handle different enum argument types
|
|
1049
|
-
if (typeof enumArg === 'string') {
|
|
1050
|
-
// This is likely a reference to an enum type name
|
|
1051
|
-
// We need to try to resolve this to actual enum values
|
|
1052
|
-
enumValues = this.resolveEnumValues(enumArg);
|
|
1053
|
-
}
|
|
1054
|
-
else if (typeof enumArg === 'object' && enumArg !== null) {
|
|
1055
|
-
// Object enum - extract values
|
|
1056
|
-
if (Array.isArray(enumArg)) {
|
|
1057
|
-
// Already an array of values
|
|
1058
|
-
enumValues = enumArg;
|
|
1059
|
-
}
|
|
1060
|
-
else {
|
|
1061
|
-
// Enum object - get all values
|
|
1062
|
-
enumValues = Object.values(enumArg);
|
|
1063
|
-
}
|
|
1064
|
-
}
|
|
1065
|
-
// If we couldn't resolve enum values, fall back to string type without enum constraint
|
|
1066
|
-
if (enumValues.length === 0) {
|
|
1067
|
-
if (!isArrayType) {
|
|
1068
|
-
schema.properties[propertyName].type = 'string';
|
|
1069
|
-
}
|
|
1070
|
-
else if (schema.properties[propertyName].items) {
|
|
1071
|
-
schema.properties[propertyName].items.type = 'string';
|
|
1072
|
-
}
|
|
1073
|
-
return;
|
|
1074
|
-
}
|
|
1075
|
-
// Determine the type based on enum values
|
|
1076
|
-
let enumType = 'string';
|
|
1077
|
-
if (enumValues.length > 0) {
|
|
1078
|
-
const firstValue = enumValues[0];
|
|
1079
|
-
if (typeof firstValue === 'number') {
|
|
1080
|
-
enumType = 'number';
|
|
1081
|
-
}
|
|
1082
|
-
else if (typeof firstValue === 'boolean') {
|
|
1083
|
-
enumType = 'boolean';
|
|
1084
|
-
}
|
|
1085
|
-
}
|
|
1086
|
-
// Apply enum to schema
|
|
1087
|
-
if (!isArrayType) {
|
|
1088
|
-
schema.properties[propertyName].type = enumType;
|
|
1089
|
-
schema.properties[propertyName].enum = enumValues;
|
|
695
|
+
transform(cls, sourceOptions) {
|
|
696
|
+
let schema = { type: 'object', properties: {} };
|
|
697
|
+
const result = this.getSourceFileByClassName(cls.name, sourceOptions);
|
|
698
|
+
if (!result?.sourceFile) {
|
|
699
|
+
console.warn(`Class ${cls.name} not found in any source file.`);
|
|
700
|
+
return { name: cls.name, schema: {} };
|
|
1090
701
|
}
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
}
|
|
1095
|
-
}
|
|
1096
|
-
/**
|
|
1097
|
-
* Attempts to resolve enum values from an enum type name.
|
|
1098
|
-
* This searches through the TypeScript AST to find the enum declaration
|
|
1099
|
-
* and extract its values.
|
|
1100
|
-
*
|
|
1101
|
-
* @param enumTypeName - The name of the enum type
|
|
1102
|
-
* @returns Array of enum values if found, empty array otherwise
|
|
1103
|
-
* @private
|
|
1104
|
-
*/
|
|
1105
|
-
resolveEnumValues(enumTypeName) {
|
|
1106
|
-
// Search for enum declarations in source files
|
|
1107
|
-
for (const sourceFile of this.program.getSourceFiles()) {
|
|
1108
|
-
if (sourceFile.isDeclarationFile)
|
|
1109
|
-
continue;
|
|
1110
|
-
if (sourceFile.fileName.includes('node_modules'))
|
|
1111
|
-
continue;
|
|
1112
|
-
const enumValues = this.findEnumValues(sourceFile, enumTypeName);
|
|
1113
|
-
if (enumValues.length > 0) {
|
|
1114
|
-
return enumValues;
|
|
1115
|
-
}
|
|
1116
|
-
}
|
|
1117
|
-
return [];
|
|
1118
|
-
}
|
|
1119
|
-
/**
|
|
1120
|
-
* Finds enum values in a specific source file.
|
|
1121
|
-
*
|
|
1122
|
-
* @param sourceFile - The source file to search
|
|
1123
|
-
* @param enumTypeName - The name of the enum to find
|
|
1124
|
-
* @returns Array of enum values if found, empty array otherwise
|
|
1125
|
-
* @private
|
|
1126
|
-
*/
|
|
1127
|
-
findEnumValues(sourceFile, enumTypeName) {
|
|
1128
|
-
let enumValues = [];
|
|
1129
|
-
const visit = (node) => {
|
|
1130
|
-
// Handle TypeScript enum declarations
|
|
1131
|
-
if (ts.isEnumDeclaration(node) && node.name?.text === enumTypeName) {
|
|
1132
|
-
enumValues = this.extractEnumValues(node);
|
|
1133
|
-
return;
|
|
1134
|
-
}
|
|
1135
|
-
// Handle const object declarations (like const Status = { ... } as const)
|
|
1136
|
-
if (ts.isVariableStatement(node)) {
|
|
1137
|
-
for (const declaration of node.declarationList.declarations) {
|
|
1138
|
-
if (ts.isVariableDeclaration(declaration) &&
|
|
1139
|
-
ts.isIdentifier(declaration.name) &&
|
|
1140
|
-
declaration.name.text === enumTypeName &&
|
|
1141
|
-
declaration.initializer) {
|
|
1142
|
-
let initializer = declaration.initializer;
|
|
1143
|
-
// Handle "as const" assertions
|
|
1144
|
-
if (ts.isAsExpression(initializer) && initializer.expression) {
|
|
1145
|
-
initializer = initializer.expression;
|
|
1146
|
-
}
|
|
1147
|
-
enumValues = this.extractObjectEnumValues(initializer);
|
|
1148
|
-
return;
|
|
1149
|
-
}
|
|
1150
|
-
}
|
|
1151
|
-
}
|
|
1152
|
-
ts.forEachChild(node, visit);
|
|
1153
|
-
};
|
|
1154
|
-
visit(sourceFile);
|
|
1155
|
-
return enumValues;
|
|
1156
|
-
}
|
|
1157
|
-
/**
|
|
1158
|
-
* Extracts values from a TypeScript enum declaration.
|
|
1159
|
-
*
|
|
1160
|
-
* @param enumNode - The enum declaration node
|
|
1161
|
-
* @returns Array of enum values
|
|
1162
|
-
* @private
|
|
1163
|
-
*/
|
|
1164
|
-
extractEnumValues(enumNode) {
|
|
1165
|
-
const values = [];
|
|
1166
|
-
for (const member of enumNode.members) {
|
|
1167
|
-
if (member.initializer) {
|
|
1168
|
-
// Handle initialized enum members
|
|
1169
|
-
if (ts.isStringLiteral(member.initializer)) {
|
|
1170
|
-
values.push(member.initializer.text);
|
|
1171
|
-
}
|
|
1172
|
-
else if (ts.isNumericLiteral(member.initializer)) {
|
|
1173
|
-
values.push(Number(member.initializer.text));
|
|
1174
|
-
}
|
|
1175
|
-
}
|
|
1176
|
-
else {
|
|
1177
|
-
// Handle auto-incremented numeric enums
|
|
1178
|
-
if (values.length === 0) {
|
|
1179
|
-
values.push(0);
|
|
1180
|
-
}
|
|
1181
|
-
else {
|
|
1182
|
-
const lastValue = values[values.length - 1];
|
|
1183
|
-
if (typeof lastValue === 'number') {
|
|
1184
|
-
values.push(lastValue + 1);
|
|
1185
|
-
}
|
|
1186
|
-
}
|
|
1187
|
-
}
|
|
1188
|
-
}
|
|
1189
|
-
return values;
|
|
1190
|
-
}
|
|
1191
|
-
/**
|
|
1192
|
-
* Extracts values from object literal enum (const object as const).
|
|
1193
|
-
*
|
|
1194
|
-
* @param initializer - The object literal initializer
|
|
1195
|
-
* @returns Array of enum values
|
|
1196
|
-
* @private
|
|
1197
|
-
*/
|
|
1198
|
-
extractObjectEnumValues(initializer) {
|
|
1199
|
-
const values = [];
|
|
1200
|
-
if (ts.isObjectLiteralExpression(initializer)) {
|
|
1201
|
-
for (const property of initializer.properties) {
|
|
1202
|
-
if (ts.isPropertyAssignment(property) && property.initializer) {
|
|
1203
|
-
if (ts.isStringLiteral(property.initializer)) {
|
|
1204
|
-
values.push(property.initializer.text);
|
|
1205
|
-
}
|
|
1206
|
-
else if (ts.isNumericLiteral(property.initializer)) {
|
|
1207
|
-
values.push(Number(property.initializer.text));
|
|
1208
|
-
}
|
|
1209
|
-
}
|
|
1210
|
-
}
|
|
1211
|
-
}
|
|
1212
|
-
return values;
|
|
1213
|
-
}
|
|
1214
|
-
/**
|
|
1215
|
-
* Applies sensible default behaviors for properties without class-validator decorators.
|
|
1216
|
-
* This allows the schema generator to work with plain TypeScript classes.
|
|
1217
|
-
*
|
|
1218
|
-
* @param property - The property information
|
|
1219
|
-
* @param schema - The schema object to modify
|
|
1220
|
-
* @private
|
|
1221
|
-
*/
|
|
1222
|
-
/**
|
|
1223
|
-
* Applies OpenAPI format specifications based on TypeScript types.
|
|
1224
|
-
* This method is called when no decorators are present to set appropriate
|
|
1225
|
-
* format values for primitive types according to OpenAPI specification.
|
|
1226
|
-
*
|
|
1227
|
-
* @param property - The property information containing type details
|
|
1228
|
-
* @param schema - The schema object to modify
|
|
1229
|
-
* @private
|
|
1230
|
-
*/
|
|
1231
|
-
applyTypeBasedFormats(property, schema) {
|
|
1232
|
-
const propertyName = property.name;
|
|
1233
|
-
const propertyType = property.type.toLowerCase();
|
|
1234
|
-
const propertySchema = schema.properties[propertyName];
|
|
1235
|
-
switch (propertyType) {
|
|
1236
|
-
case constants.jsPrimitives.Number.value:
|
|
1237
|
-
propertySchema.format = constants.jsPrimitives.Number.format;
|
|
1238
|
-
break;
|
|
1239
|
-
case constants.jsPrimitives.BigInt.value:
|
|
1240
|
-
propertySchema.format = constants.jsPrimitives.BigInt.format;
|
|
1241
|
-
break;
|
|
1242
|
-
case constants.jsPrimitives.Date.value:
|
|
1243
|
-
propertySchema.format = constants.jsPrimitives.Date.format;
|
|
1244
|
-
break;
|
|
1245
|
-
case constants.jsPrimitives.Buffer.value:
|
|
1246
|
-
case constants.jsPrimitives.Uint8Array.value:
|
|
1247
|
-
case constants.jsPrimitives.File.value:
|
|
1248
|
-
case constants.jsPrimitives.UploadFile.value:
|
|
1249
|
-
propertySchema.format = constants.jsPrimitives.UploadFile.format;
|
|
1250
|
-
break;
|
|
1251
|
-
}
|
|
1252
|
-
}
|
|
1253
|
-
/**
|
|
1254
|
-
* Determines if a property should be required based on decorators and optional status.
|
|
1255
|
-
*
|
|
1256
|
-
* Logic:
|
|
1257
|
-
* - If property has IsNotEmpty or ArrayNotEmpty decorator, it's required (handled in applyDecorators)
|
|
1258
|
-
* - Otherwise, the property is not required (preserving original behavior)
|
|
1259
|
-
* - The isOptional information is stored for future use and documentation
|
|
1260
|
-
*
|
|
1261
|
-
* @param property - The property information
|
|
1262
|
-
* @param schema - The schema object to modify
|
|
1263
|
-
* @private
|
|
1264
|
-
*/
|
|
1265
|
-
determineRequiredStatus(property, schema) {
|
|
1266
|
-
const propertyName = property.name;
|
|
1267
|
-
// Check if already marked as required by IsNotEmpty or ArrayNotEmpty decorator
|
|
1268
|
-
const isAlreadyRequired = schema.required.includes(propertyName);
|
|
1269
|
-
// If already required by decorators, don't change it
|
|
1270
|
-
if (isAlreadyRequired) {
|
|
1271
|
-
return;
|
|
1272
|
-
}
|
|
1273
|
-
// If property is optional (has ?), it should not be required unless explicitly marked
|
|
1274
|
-
if (property.isOptional) {
|
|
1275
|
-
return;
|
|
1276
|
-
}
|
|
1277
|
-
// If property is not optional and not already required, make it required
|
|
1278
|
-
schema.required.push(propertyName);
|
|
702
|
+
const properties = this.getPropertiesByClassDeclaration(result.node);
|
|
703
|
+
schema = this.getSchemaFromProperties({ properties });
|
|
704
|
+
return { name: cls.name, schema };
|
|
1279
705
|
}
|
|
1280
706
|
}
|
|
707
|
+
function transform(cls, options) {
|
|
708
|
+
// Use the singleton instance instead of creating a temporary one
|
|
709
|
+
const transformer = SchemaTransformer.getInstance(undefined, options);
|
|
710
|
+
return transformer.transform(cls, options?.sourceOptions);
|
|
711
|
+
}
|
|
712
|
+
|
|
1281
713
|
/**
|
|
1282
|
-
*
|
|
1283
|
-
*
|
|
1284
|
-
* @param cls - The class constructor function to transform
|
|
1285
|
-
* @param options - Optional configuration for memory management
|
|
1286
|
-
* @returns Object containing the class name and its corresponding JSON schema
|
|
1287
|
-
*
|
|
1288
|
-
* @example
|
|
1289
|
-
* ```typescript
|
|
1290
|
-
* import { transform } from 'class-validator-to-open-api'
|
|
1291
|
-
* import { User } from './entities/user.js'
|
|
1292
|
-
*
|
|
1293
|
-
* const schema = transform(User)
|
|
1294
|
-
* console.log(schema)
|
|
1295
|
-
* ```
|
|
1296
|
-
*
|
|
1297
|
-
* @example
|
|
1298
|
-
* ```typescript
|
|
1299
|
-
* // With memory optimization
|
|
1300
|
-
* const schema = transform(User, { maxCacheSize: 50, autoCleanup: true })
|
|
1301
|
-
* ```
|
|
1302
|
-
*
|
|
1303
|
-
* @public
|
|
714
|
+
* Pure TypeScript class without any decorators
|
|
715
|
+
* Used to test basic type inference and transformation
|
|
1304
716
|
*/
|
|
1305
|
-
|
|
1306
|
-
|
|
717
|
+
class PureUser {
|
|
718
|
+
id;
|
|
719
|
+
name;
|
|
720
|
+
email;
|
|
721
|
+
age;
|
|
722
|
+
isActive;
|
|
723
|
+
tags;
|
|
724
|
+
metadata;
|
|
725
|
+
createdAt;
|
|
726
|
+
phone;
|
|
727
|
+
bio;
|
|
728
|
+
}
|
|
729
|
+
/**
|
|
730
|
+
* Pure TypeScript class with primitive types only
|
|
731
|
+
*/
|
|
732
|
+
class SimplePerson {
|
|
733
|
+
firstName;
|
|
734
|
+
lastName;
|
|
735
|
+
age;
|
|
736
|
+
isEmployed;
|
|
737
|
+
}
|
|
738
|
+
/**
|
|
739
|
+
* Pure TypeScript class with arrays
|
|
740
|
+
*/
|
|
741
|
+
class Product {
|
|
742
|
+
id;
|
|
743
|
+
name;
|
|
744
|
+
price;
|
|
745
|
+
categories;
|
|
746
|
+
scores;
|
|
747
|
+
isAvailable;
|
|
748
|
+
description;
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
/**
|
|
752
|
+
* Additional test classes for pure TypeScript classes tests
|
|
753
|
+
* These classes are used in the pure-classes.test.ts file
|
|
754
|
+
*/
|
|
755
|
+
class OptionalOnlyClass {
|
|
756
|
+
optionalProp;
|
|
757
|
+
anotherOptional;
|
|
758
|
+
}
|
|
759
|
+
class UnionTypeClass {
|
|
760
|
+
stringOrNumber;
|
|
761
|
+
optionalUnion;
|
|
1307
762
|
}
|
|
1308
763
|
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
764
|
+
/**
|
|
765
|
+
* Test cases for pure TypeScript classes (without decorators)
|
|
766
|
+
*/
|
|
767
|
+
node_test.describe('Pure TypeScript Classes', () => {
|
|
768
|
+
node_test.test('should transform PureUser class correctly', () => {
|
|
769
|
+
const result = transform(PureUser);
|
|
770
|
+
const schema = result.schema;
|
|
771
|
+
assert.strictEqual(schema.type, 'object');
|
|
772
|
+
assert.ok(schema.properties);
|
|
773
|
+
// Check basic properties
|
|
774
|
+
assert.strictEqual(schema.properties.id.type, 'number');
|
|
775
|
+
assert.strictEqual(schema.properties.name.type, 'string');
|
|
776
|
+
assert.strictEqual(schema.properties.email.type, 'string');
|
|
777
|
+
assert.strictEqual(schema.properties.age.type, 'number');
|
|
778
|
+
assert.strictEqual(schema.properties.isActive.type, 'boolean');
|
|
779
|
+
// Check array properties
|
|
780
|
+
assert.strictEqual(schema.properties.tags.type, 'array');
|
|
781
|
+
assert.strictEqual(schema.properties.tags.items.type, 'string');
|
|
782
|
+
// Check required fields (all non-optional fields should be required)
|
|
783
|
+
const expectedRequired = [
|
|
784
|
+
'id',
|
|
785
|
+
'name',
|
|
786
|
+
'email',
|
|
787
|
+
'age',
|
|
788
|
+
'isActive',
|
|
789
|
+
'tags',
|
|
790
|
+
'metadata',
|
|
791
|
+
'createdAt',
|
|
792
|
+
];
|
|
793
|
+
assert.deepStrictEqual(schema.required?.sort(), expectedRequired.sort());
|
|
794
|
+
});
|
|
795
|
+
node_test.test('should transform SimplePerson class correctly', () => {
|
|
796
|
+
const result = transform(SimplePerson);
|
|
797
|
+
const schema = result.schema;
|
|
798
|
+
assert.strictEqual(schema.type, 'object');
|
|
799
|
+
assert.ok(schema.properties);
|
|
800
|
+
assert.strictEqual(schema.properties.firstName.type, 'string');
|
|
801
|
+
assert.strictEqual(schema.properties.lastName.type, 'string');
|
|
802
|
+
assert.strictEqual(schema.properties.age.type, 'number');
|
|
803
|
+
assert.strictEqual(schema.properties.isEmployed.type, 'boolean');
|
|
804
|
+
assert.deepStrictEqual(schema.required?.sort(), ['firstName', 'lastName', 'age', 'isEmployed'].sort());
|
|
805
|
+
});
|
|
806
|
+
node_test.test('should transform Product class correctly', () => {
|
|
807
|
+
const result = transform(Product);
|
|
808
|
+
const schema = result.schema;
|
|
809
|
+
assert.strictEqual(schema.type, 'object');
|
|
810
|
+
assert.ok(schema.properties);
|
|
811
|
+
// Check basic properties
|
|
812
|
+
assert.strictEqual(schema.properties.id.type, 'number');
|
|
813
|
+
assert.strictEqual(schema.properties.name.type, 'string');
|
|
814
|
+
assert.strictEqual(schema.properties.price.type, 'number');
|
|
815
|
+
assert.strictEqual(schema.properties.isAvailable.type, 'boolean');
|
|
816
|
+
// Check array property
|
|
817
|
+
assert.strictEqual(schema.properties.categories.type, 'array');
|
|
818
|
+
assert.strictEqual(schema.properties.categories.items.type, 'string');
|
|
819
|
+
assert.strictEqual(schema.properties.scores.type, 'array');
|
|
820
|
+
assert.strictEqual(schema.properties.scores.items.type, 'number');
|
|
821
|
+
// Check optional fields are not in required
|
|
822
|
+
const requiredFields = schema.required || [];
|
|
823
|
+
assert.ok(!requiredFields.includes('description'));
|
|
824
|
+
});
|
|
825
|
+
node_test.test('should handle class with only optional properties', () => {
|
|
826
|
+
const result = transform(OptionalOnlyClass);
|
|
827
|
+
const schema = result.schema;
|
|
828
|
+
assert.strictEqual(schema.type, 'object');
|
|
829
|
+
assert.ok(schema.properties);
|
|
830
|
+
assert.strictEqual(schema.properties.optionalProp.type, 'string');
|
|
831
|
+
assert.strictEqual(schema.properties.anotherOptional.type, 'number');
|
|
832
|
+
// Should have no required fields
|
|
833
|
+
assert.ok(!schema.required || schema.required.length === 0);
|
|
834
|
+
});
|
|
835
|
+
node_test.test('should handle union types', () => {
|
|
836
|
+
const result = transform(UnionTypeClass);
|
|
837
|
+
const schema = result.schema;
|
|
838
|
+
assert.strictEqual(schema.type, 'object');
|
|
839
|
+
assert.ok(schema.properties);
|
|
840
|
+
// Union types should be handled appropriately
|
|
841
|
+
assert.ok(schema.properties.stringOrNumber);
|
|
842
|
+
assert.ok(schema.properties.optionalUnion);
|
|
843
|
+
});
|
|
844
|
+
});
|
|
845
|
+
|
|
846
|
+
/******************************************************************************
|
|
847
|
+
Copyright (c) Microsoft Corporation.
|
|
848
|
+
|
|
849
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
850
|
+
purpose with or without fee is hereby granted.
|
|
851
|
+
|
|
852
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
853
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
854
|
+
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
855
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
856
|
+
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
857
|
+
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
858
|
+
PERFORMANCE OF THIS SOFTWARE.
|
|
859
|
+
***************************************************************************** */
|
|
860
|
+
/* global Reflect, Promise, SuppressedError, Symbol, Iterator */
|
|
861
|
+
|
|
862
|
+
|
|
863
|
+
function __decorate(decorators, target, key, desc) {
|
|
864
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
865
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
866
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
867
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
|
871
|
+
var e = new Error(message);
|
|
872
|
+
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
873
|
+
};
|
|
874
|
+
|
|
875
|
+
var UserStatus;
|
|
876
|
+
(function (UserStatus) {
|
|
877
|
+
UserStatus["ACTIVE"] = "active";
|
|
878
|
+
UserStatus["INACTIVE"] = "inactive";
|
|
879
|
+
UserStatus["PENDING"] = "pending";
|
|
880
|
+
UserStatus["SUSPENDED"] = "suspended";
|
|
881
|
+
})(UserStatus || (UserStatus = {}));
|
|
882
|
+
var Priority;
|
|
883
|
+
(function (Priority) {
|
|
884
|
+
Priority[Priority["LOW"] = 1] = "LOW";
|
|
885
|
+
Priority[Priority["MEDIUM"] = 2] = "MEDIUM";
|
|
886
|
+
Priority[Priority["HIGH"] = 3] = "HIGH";
|
|
887
|
+
Priority[Priority["CRITICAL"] = 4] = "CRITICAL";
|
|
888
|
+
})(Priority || (Priority = {}));
|
|
889
|
+
class DecoratedAddress {
|
|
890
|
+
street;
|
|
891
|
+
city;
|
|
892
|
+
state;
|
|
893
|
+
zipCode;
|
|
894
|
+
country;
|
|
1312
895
|
}
|
|
1313
|
-
|
|
1314
|
-
|
|
896
|
+
__decorate([
|
|
897
|
+
classValidator.IsString(),
|
|
898
|
+
classValidator.Length(5, 100)
|
|
899
|
+
], DecoratedAddress.prototype, "street", void 0);
|
|
900
|
+
__decorate([
|
|
901
|
+
classValidator.IsString(),
|
|
902
|
+
classValidator.Length(2, 50)
|
|
903
|
+
], DecoratedAddress.prototype, "city", void 0);
|
|
904
|
+
__decorate([
|
|
905
|
+
classValidator.IsString(),
|
|
906
|
+
classValidator.Length(2, 50)
|
|
907
|
+
], DecoratedAddress.prototype, "state", void 0);
|
|
908
|
+
__decorate([
|
|
909
|
+
classValidator.IsString(),
|
|
910
|
+
classValidator.Matches(/^\d{5}(-\d{4})?$/)
|
|
911
|
+
], DecoratedAddress.prototype, "zipCode", void 0);
|
|
912
|
+
__decorate([
|
|
913
|
+
classValidator.IsString(),
|
|
914
|
+
classValidator.Length(2, 50)
|
|
915
|
+
], DecoratedAddress.prototype, "country", void 0);
|
|
916
|
+
class DecoratedUser {
|
|
1315
917
|
id;
|
|
1316
918
|
name;
|
|
1317
919
|
email;
|
|
1318
920
|
age;
|
|
921
|
+
status;
|
|
1319
922
|
isActive;
|
|
1320
923
|
tags;
|
|
924
|
+
address;
|
|
1321
925
|
createdAt;
|
|
1322
|
-
|
|
926
|
+
updatedAt;
|
|
1323
927
|
}
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
928
|
+
__decorate([
|
|
929
|
+
classValidator.IsNumber(),
|
|
930
|
+
classValidator.IsPositive()
|
|
931
|
+
], DecoratedUser.prototype, "id", void 0);
|
|
932
|
+
__decorate([
|
|
933
|
+
classValidator.IsString(),
|
|
934
|
+
classValidator.Length(2, 50)
|
|
935
|
+
], DecoratedUser.prototype, "name", void 0);
|
|
936
|
+
__decorate([
|
|
937
|
+
classValidator.IsEmail()
|
|
938
|
+
], DecoratedUser.prototype, "email", void 0);
|
|
939
|
+
__decorate([
|
|
940
|
+
classValidator.IsNumber(),
|
|
941
|
+
classValidator.Min(18),
|
|
942
|
+
classValidator.Max(120)
|
|
943
|
+
], DecoratedUser.prototype, "age", void 0);
|
|
944
|
+
__decorate([
|
|
945
|
+
classValidator.IsEnum(UserStatus)
|
|
946
|
+
], DecoratedUser.prototype, "status", void 0);
|
|
947
|
+
__decorate([
|
|
948
|
+
classValidator.IsBoolean(),
|
|
949
|
+
classValidator.IsOptional()
|
|
950
|
+
], DecoratedUser.prototype, "isActive", void 0);
|
|
951
|
+
__decorate([
|
|
952
|
+
classValidator.IsArray(),
|
|
953
|
+
classValidator.IsString({ each: true })
|
|
954
|
+
], DecoratedUser.prototype, "tags", void 0);
|
|
955
|
+
__decorate([
|
|
956
|
+
classValidator.ValidateNested()
|
|
957
|
+
], DecoratedUser.prototype, "address", void 0);
|
|
958
|
+
__decorate([
|
|
959
|
+
classValidator.IsDate()
|
|
960
|
+
], DecoratedUser.prototype, "createdAt", void 0);
|
|
961
|
+
__decorate([
|
|
962
|
+
classValidator.IsOptional(),
|
|
963
|
+
classValidator.IsDate()
|
|
964
|
+
], DecoratedUser.prototype, "updatedAt", void 0);
|
|
965
|
+
class DecoratedProduct {
|
|
966
|
+
id;
|
|
967
|
+
name;
|
|
968
|
+
description;
|
|
969
|
+
price;
|
|
970
|
+
currency;
|
|
971
|
+
categories;
|
|
972
|
+
inStock;
|
|
973
|
+
quantity;
|
|
974
|
+
images;
|
|
1327
975
|
}
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
976
|
+
__decorate([
|
|
977
|
+
classValidator.IsNumber(),
|
|
978
|
+
classValidator.IsPositive()
|
|
979
|
+
], DecoratedProduct.prototype, "id", void 0);
|
|
980
|
+
__decorate([
|
|
981
|
+
classValidator.IsString(),
|
|
982
|
+
classValidator.Length(3, 100)
|
|
983
|
+
], DecoratedProduct.prototype, "name", void 0);
|
|
984
|
+
__decorate([
|
|
985
|
+
classValidator.IsString(),
|
|
986
|
+
classValidator.Length(10, 500)
|
|
987
|
+
], DecoratedProduct.prototype, "description", void 0);
|
|
988
|
+
__decorate([
|
|
989
|
+
classValidator.IsNumber(),
|
|
990
|
+
classValidator.Min(0)
|
|
991
|
+
], DecoratedProduct.prototype, "price", void 0);
|
|
992
|
+
__decorate([
|
|
993
|
+
classValidator.IsString(),
|
|
994
|
+
classValidator.Length(3, 20)
|
|
995
|
+
], DecoratedProduct.prototype, "currency", void 0);
|
|
996
|
+
__decorate([
|
|
997
|
+
classValidator.IsArray(),
|
|
998
|
+
classValidator.IsString({ each: true })
|
|
999
|
+
], DecoratedProduct.prototype, "categories", void 0);
|
|
1000
|
+
__decorate([
|
|
1001
|
+
classValidator.IsBoolean()
|
|
1002
|
+
], DecoratedProduct.prototype, "inStock", void 0);
|
|
1003
|
+
__decorate([
|
|
1004
|
+
classValidator.IsOptional(),
|
|
1005
|
+
classValidator.IsNumber(),
|
|
1006
|
+
classValidator.Min(0)
|
|
1007
|
+
], DecoratedProduct.prototype, "quantity", void 0);
|
|
1008
|
+
__decorate([
|
|
1009
|
+
classValidator.IsOptional(),
|
|
1010
|
+
classValidator.IsArray(),
|
|
1011
|
+
classValidator.IsString({ each: true })
|
|
1012
|
+
], DecoratedProduct.prototype, "images", void 0);
|
|
1013
|
+
class DecoratedTask {
|
|
1014
|
+
id;
|
|
1015
|
+
title;
|
|
1016
|
+
description;
|
|
1017
|
+
priority;
|
|
1018
|
+
completed;
|
|
1019
|
+
dueDate;
|
|
1020
|
+
assignedTo;
|
|
1021
|
+
tags;
|
|
1022
|
+
createdAt;
|
|
1023
|
+
completedAt;
|
|
1337
1024
|
}
|
|
1338
|
-
|
|
1339
|
-
|
|
1025
|
+
__decorate([
|
|
1026
|
+
classValidator.IsNumber(),
|
|
1027
|
+
classValidator.IsPositive()
|
|
1028
|
+
], DecoratedTask.prototype, "id", void 0);
|
|
1029
|
+
__decorate([
|
|
1030
|
+
classValidator.IsString(),
|
|
1031
|
+
classValidator.Length(5, 100)
|
|
1032
|
+
], DecoratedTask.prototype, "title", void 0);
|
|
1033
|
+
__decorate([
|
|
1034
|
+
classValidator.IsString(),
|
|
1035
|
+
classValidator.Length(10, 1000)
|
|
1036
|
+
], DecoratedTask.prototype, "description", void 0);
|
|
1037
|
+
__decorate([
|
|
1038
|
+
classValidator.IsEnum(Priority)
|
|
1039
|
+
], DecoratedTask.prototype, "priority", void 0);
|
|
1040
|
+
__decorate([
|
|
1041
|
+
classValidator.IsBoolean()
|
|
1042
|
+
], DecoratedTask.prototype, "completed", void 0);
|
|
1043
|
+
__decorate([
|
|
1044
|
+
classValidator.IsDate()
|
|
1045
|
+
], DecoratedTask.prototype, "dueDate", void 0);
|
|
1046
|
+
__decorate([
|
|
1047
|
+
classValidator.IsOptional(),
|
|
1048
|
+
classValidator.ValidateNested()
|
|
1049
|
+
], DecoratedTask.prototype, "assignedTo", void 0);
|
|
1050
|
+
__decorate([
|
|
1051
|
+
classValidator.IsArray(),
|
|
1052
|
+
classValidator.IsString({ each: true }),
|
|
1053
|
+
classValidator.IsOptional()
|
|
1054
|
+
], DecoratedTask.prototype, "tags", void 0);
|
|
1055
|
+
__decorate([
|
|
1056
|
+
classValidator.IsDate()
|
|
1057
|
+
], DecoratedTask.prototype, "createdAt", void 0);
|
|
1058
|
+
__decorate([
|
|
1059
|
+
classValidator.IsOptional(),
|
|
1060
|
+
classValidator.IsDate()
|
|
1061
|
+
], DecoratedTask.prototype, "completedAt", void 0);
|
|
1062
|
+
|
|
1063
|
+
/**
|
|
1064
|
+
* Test cases for decorated classes using class-validator
|
|
1065
|
+
*/
|
|
1066
|
+
node_test.describe('Decorated Classes with class-validator', () => {
|
|
1067
|
+
node_test.test('should transform DecoratedAddress with validation constraints', () => {
|
|
1068
|
+
const result = transform(DecoratedAddress);
|
|
1069
|
+
const schema = result.schema;
|
|
1070
|
+
assert.strictEqual(schema.type, 'object');
|
|
1071
|
+
assert.ok(schema.properties);
|
|
1072
|
+
assert.strictEqual(schema.properties.street.minLength, 5);
|
|
1073
|
+
assert.strictEqual(schema.properties.street.maxLength, 100);
|
|
1074
|
+
assert.strictEqual(schema.properties.city.minLength, 2);
|
|
1075
|
+
assert.strictEqual(schema.properties.city.maxLength, 50);
|
|
1076
|
+
assert.strictEqual(schema.properties.state.minLength, 2);
|
|
1077
|
+
assert.strictEqual(schema.properties.state.maxLength, 50);
|
|
1078
|
+
assert.strictEqual(schema.properties.country.minLength, 2);
|
|
1079
|
+
assert.strictEqual(schema.properties.country.maxLength, 50);
|
|
1080
|
+
assert.strictEqual(schema.properties.zipCode.type, 'string');
|
|
1081
|
+
});
|
|
1082
|
+
node_test.test('should transform DecoratedUser with comprehensive validation', () => {
|
|
1083
|
+
const result = transform(DecoratedUser);
|
|
1084
|
+
const schema = result.schema;
|
|
1085
|
+
assert.strictEqual(schema.type, 'object');
|
|
1086
|
+
assert.ok(schema.properties);
|
|
1087
|
+
assert.strictEqual(schema.properties.email.format, 'email');
|
|
1088
|
+
assert.strictEqual(schema.properties.age.minimum, 18);
|
|
1089
|
+
assert.strictEqual(schema.properties.age.maximum, 120);
|
|
1090
|
+
assert.strictEqual(schema.properties.id.minimum, 0);
|
|
1091
|
+
assert.strictEqual(schema.properties.name.minLength, 2);
|
|
1092
|
+
assert.strictEqual(schema.properties.name.maxLength, 50);
|
|
1093
|
+
assert.ok(schema.properties.status);
|
|
1094
|
+
assert.strictEqual(schema.properties.tags.type, 'array');
|
|
1095
|
+
assert.strictEqual(schema.properties.tags.items.type, 'string');
|
|
1096
|
+
assert.strictEqual(schema.properties.address.type, 'object');
|
|
1097
|
+
assert.strictEqual(schema.properties.createdAt.type, 'string');
|
|
1098
|
+
assert.strictEqual(schema.properties.createdAt.format, 'date-time');
|
|
1099
|
+
const requiredFields = schema.required || [];
|
|
1100
|
+
assert.ok(!requiredFields.includes('isActive'));
|
|
1101
|
+
assert.ok(!requiredFields.includes('updatedAt'));
|
|
1102
|
+
});
|
|
1103
|
+
node_test.test('should transform DecoratedProduct with validation constraints', () => {
|
|
1104
|
+
const result = transform(DecoratedProduct);
|
|
1105
|
+
const schema = result.schema;
|
|
1106
|
+
assert.strictEqual(schema.type, 'object');
|
|
1107
|
+
assert.ok(schema.properties);
|
|
1108
|
+
assert.strictEqual(schema.properties.id.minimum, 0);
|
|
1109
|
+
assert.strictEqual(schema.properties.price.minimum, 0);
|
|
1110
|
+
// Check string length constraints
|
|
1111
|
+
assert.strictEqual(schema.properties.name.minLength, 3);
|
|
1112
|
+
assert.strictEqual(schema.properties.name.maxLength, 100);
|
|
1113
|
+
assert.strictEqual(schema.properties.description.minLength, 10);
|
|
1114
|
+
assert.strictEqual(schema.properties.description.maxLength, 500);
|
|
1115
|
+
assert.strictEqual(schema.properties.currency.minLength, 3);
|
|
1116
|
+
assert.strictEqual(schema.properties.currency.maxLength, 20);
|
|
1117
|
+
assert.strictEqual(schema.properties.categories.type, 'array');
|
|
1118
|
+
assert.strictEqual(schema.properties.categories.items.type, 'string');
|
|
1119
|
+
assert.strictEqual(schema.properties.inStock.type, 'boolean');
|
|
1120
|
+
const requiredFields = schema.required || [];
|
|
1121
|
+
assert.ok(!requiredFields.includes('quantity'));
|
|
1122
|
+
assert.ok(!requiredFields.includes('images'));
|
|
1123
|
+
});
|
|
1124
|
+
node_test.test('should transform DecoratedTask with enum and nested validation', () => {
|
|
1125
|
+
const result = transform(DecoratedTask);
|
|
1126
|
+
const schema = result.schema;
|
|
1127
|
+
assert.strictEqual(schema.type, 'object');
|
|
1128
|
+
assert.ok(schema.properties);
|
|
1129
|
+
// Check string length constraints
|
|
1130
|
+
assert.strictEqual(schema.properties.title.minLength, 5);
|
|
1131
|
+
assert.strictEqual(schema.properties.title.maxLength, 100);
|
|
1132
|
+
assert.strictEqual(schema.properties.description.minLength, 10);
|
|
1133
|
+
assert.strictEqual(schema.properties.description.maxLength, 1000);
|
|
1134
|
+
assert.ok(schema.properties.priority);
|
|
1135
|
+
assert.strictEqual(schema.properties.completed.type, 'boolean');
|
|
1136
|
+
assert.strictEqual(schema.properties.assignedTo?.type, 'object');
|
|
1137
|
+
assert.strictEqual(schema.properties.dueDate.type, 'string');
|
|
1138
|
+
assert.strictEqual(schema.properties.dueDate.format, 'date-time');
|
|
1139
|
+
assert.strictEqual(schema.properties.createdAt.type, 'string');
|
|
1140
|
+
assert.strictEqual(schema.properties.createdAt.format, 'date-time');
|
|
1141
|
+
const requiredFields = schema.required || [];
|
|
1142
|
+
assert.ok(!requiredFields.includes('assignedTo'));
|
|
1143
|
+
assert.ok(!requiredFields.includes('tags'));
|
|
1144
|
+
assert.ok(!requiredFields.includes('completedAt'));
|
|
1145
|
+
});
|
|
1146
|
+
/* Las pruebas de enums se omiten ya que el decorador @IsEnum no está implementado aún */
|
|
1147
|
+
});
|
|
1148
|
+
|
|
1149
|
+
/**
|
|
1150
|
+
* Nested TypeScript classes to test object relationships
|
|
1151
|
+
*/
|
|
1152
|
+
class Address {
|
|
1153
|
+
street;
|
|
1154
|
+
city;
|
|
1155
|
+
state;
|
|
1156
|
+
zipCode;
|
|
1157
|
+
country;
|
|
1340
1158
|
}
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1159
|
+
class Role {
|
|
1160
|
+
id;
|
|
1161
|
+
name;
|
|
1162
|
+
permissions;
|
|
1163
|
+
level;
|
|
1346
1164
|
}
|
|
1347
|
-
|
|
1348
|
-
|
|
1165
|
+
class Company {
|
|
1166
|
+
name;
|
|
1167
|
+
industry;
|
|
1168
|
+
foundedYear;
|
|
1169
|
+
employees;
|
|
1349
1170
|
}
|
|
1171
|
+
class NestedUser {
|
|
1172
|
+
id;
|
|
1173
|
+
name;
|
|
1174
|
+
email;
|
|
1175
|
+
address;
|
|
1176
|
+
roles;
|
|
1177
|
+
company;
|
|
1178
|
+
alternativeAddresses;
|
|
1179
|
+
emergencyContact;
|
|
1180
|
+
}
|
|
1181
|
+
/**
|
|
1182
|
+
* Deep nesting example
|
|
1183
|
+
*/
|
|
1184
|
+
class Department {
|
|
1185
|
+
id;
|
|
1186
|
+
name;
|
|
1187
|
+
budget;
|
|
1188
|
+
}
|
|
1189
|
+
class Team {
|
|
1190
|
+
id;
|
|
1191
|
+
name;
|
|
1192
|
+
department;
|
|
1193
|
+
members;
|
|
1194
|
+
}
|
|
1195
|
+
class TeamMember {
|
|
1196
|
+
id;
|
|
1197
|
+
name;
|
|
1198
|
+
email;
|
|
1199
|
+
role;
|
|
1200
|
+
startDate;
|
|
1201
|
+
}
|
|
1202
|
+
class Organization {
|
|
1203
|
+
id;
|
|
1204
|
+
name;
|
|
1205
|
+
teams;
|
|
1206
|
+
headquarters;
|
|
1207
|
+
subsidiaries;
|
|
1208
|
+
}
|
|
1209
|
+
|
|
1210
|
+
/**
|
|
1211
|
+
* Test cases for nested TypeScript classes (complex object relationships)
|
|
1212
|
+
*/
|
|
1213
|
+
node_test.describe('Nested TypeScript Classes', () => {
|
|
1214
|
+
node_test.test('should transform Address class correctly', () => {
|
|
1215
|
+
const result = transform(Address);
|
|
1216
|
+
const schema = result.schema;
|
|
1217
|
+
assert.strictEqual(schema.type, 'object');
|
|
1218
|
+
assert.ok(schema.properties);
|
|
1219
|
+
const expectedProperties = ['street', 'city', 'state', 'zipCode', 'country'];
|
|
1220
|
+
expectedProperties.forEach(prop => {
|
|
1221
|
+
assert.ok(schema.properties[prop]);
|
|
1222
|
+
assert.strictEqual(schema.properties[prop].type, 'string');
|
|
1223
|
+
});
|
|
1224
|
+
assert.deepStrictEqual(schema.required?.sort(), expectedProperties.sort());
|
|
1225
|
+
});
|
|
1226
|
+
node_test.test('should transform Role class correctly', () => {
|
|
1227
|
+
const result = transform(Role);
|
|
1228
|
+
const schema = result.schema;
|
|
1229
|
+
assert.strictEqual(schema.type, 'object');
|
|
1230
|
+
assert.ok(schema.properties);
|
|
1231
|
+
assert.strictEqual(schema.properties.id.type, 'number');
|
|
1232
|
+
assert.strictEqual(schema.properties.name.type, 'string');
|
|
1233
|
+
assert.strictEqual(schema.properties.permissions.type, 'array');
|
|
1234
|
+
assert.strictEqual(schema.properties.permissions.items.type, 'string');
|
|
1235
|
+
assert.strictEqual(schema.properties.level.type, 'number');
|
|
1236
|
+
});
|
|
1237
|
+
node_test.test('should transform Company class correctly', () => {
|
|
1238
|
+
const result = transform(Company);
|
|
1239
|
+
const schema = result.schema;
|
|
1240
|
+
assert.strictEqual(schema.type, 'object');
|
|
1241
|
+
assert.ok(schema.properties);
|
|
1242
|
+
assert.strictEqual(schema.properties.name.type, 'string');
|
|
1243
|
+
assert.strictEqual(schema.properties.industry.type, 'string');
|
|
1244
|
+
assert.strictEqual(schema.properties.foundedYear.type, 'number');
|
|
1245
|
+
assert.strictEqual(schema.properties.employees.type, 'number');
|
|
1246
|
+
});
|
|
1247
|
+
node_test.test('should transform NestedUser class correctly', () => {
|
|
1248
|
+
const result = transform(NestedUser);
|
|
1249
|
+
const schema = result.schema;
|
|
1250
|
+
assert.strictEqual(schema.type, 'object');
|
|
1251
|
+
assert.ok(schema.properties);
|
|
1252
|
+
// Check nested object property
|
|
1253
|
+
assert.strictEqual(schema.properties.address.type, 'object');
|
|
1254
|
+
assert.ok(schema.properties.address.properties);
|
|
1255
|
+
// Check array of objects
|
|
1256
|
+
assert.strictEqual(schema.properties.roles.type, 'array');
|
|
1257
|
+
assert.strictEqual(schema.properties.roles.items.type, 'object');
|
|
1258
|
+
// Check company nested object
|
|
1259
|
+
assert.strictEqual(schema.properties.company.type, 'object');
|
|
1260
|
+
assert.ok(schema.properties.company.properties);
|
|
1261
|
+
// Check array of nested objects
|
|
1262
|
+
assert.strictEqual(schema.properties.alternativeAddresses.type, 'array');
|
|
1263
|
+
assert.strictEqual(schema.properties.alternativeAddresses.items.type, 'object');
|
|
1264
|
+
// Check optional nested object
|
|
1265
|
+
const requiredFields = schema.required || [];
|
|
1266
|
+
assert.ok(!requiredFields.includes('emergencyContact'));
|
|
1267
|
+
});
|
|
1268
|
+
node_test.test('should transform Organization class with deep nesting correctly', () => {
|
|
1269
|
+
const result = transform(Organization);
|
|
1270
|
+
const schema = result.schema;
|
|
1271
|
+
assert.strictEqual(schema.type, 'object');
|
|
1272
|
+
assert.ok(schema.properties);
|
|
1273
|
+
// Check teams array with nested objects
|
|
1274
|
+
assert.strictEqual(schema.properties.teams.type, 'array');
|
|
1275
|
+
assert.strictEqual(schema.properties.teams.items.type, 'object');
|
|
1276
|
+
// Check headquarters nested object
|
|
1277
|
+
assert.strictEqual(schema.properties.headquarters.type, 'object');
|
|
1278
|
+
// Check subsidiaries array with inline objects
|
|
1279
|
+
assert.strictEqual(schema.properties.subsidiaries.type, 'array');
|
|
1280
|
+
assert.strictEqual(schema.properties.subsidiaries.items.type, 'object');
|
|
1281
|
+
});
|
|
1282
|
+
node_test.test('should transform Team class with multiple nested levels', () => {
|
|
1283
|
+
const result = transform(Team);
|
|
1284
|
+
const schema = result.schema;
|
|
1285
|
+
assert.strictEqual(schema.type, 'object');
|
|
1286
|
+
assert.ok(schema.properties);
|
|
1287
|
+
// Check nested department
|
|
1288
|
+
assert.strictEqual(schema.properties.department.type, 'object');
|
|
1289
|
+
// Check array of team members
|
|
1290
|
+
assert.strictEqual(schema.properties.members.type, 'array');
|
|
1291
|
+
assert.strictEqual(schema.properties.members.items.type, 'object');
|
|
1292
|
+
});
|
|
1293
|
+
node_test.test('should transform TeamMember class correctly', () => {
|
|
1294
|
+
const result = transform(TeamMember);
|
|
1295
|
+
const schema = result.schema;
|
|
1296
|
+
assert.strictEqual(schema.type, 'object');
|
|
1297
|
+
assert.ok(schema.properties);
|
|
1298
|
+
// Check Date type transformation
|
|
1299
|
+
assert.strictEqual(schema.properties.startDate.type, 'string');
|
|
1300
|
+
assert.strictEqual(schema.properties.startDate.format, 'date-time');
|
|
1301
|
+
});
|
|
1302
|
+
node_test.test('should transform Department class correctly', () => {
|
|
1303
|
+
const result = transform(Department);
|
|
1304
|
+
const schema = result.schema;
|
|
1305
|
+
assert.strictEqual(schema.type, 'object');
|
|
1306
|
+
assert.ok(schema.properties);
|
|
1307
|
+
assert.strictEqual(schema.properties.id.type, 'number');
|
|
1308
|
+
assert.strictEqual(schema.properties.name.type, 'string');
|
|
1309
|
+
assert.strictEqual(schema.properties.budget.type, 'number');
|
|
1310
|
+
});
|
|
1311
|
+
});
|
|
1312
|
+
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicnVuLmpzIiwic291cmNlcyI6WyIuLi9zcmMvdHJhbnNmb3JtZXIuZml4dHVyZXMudHMiLCIuLi9zcmMvdHJhbnNmb3JtZXIudHMiLCIuLi9zcmMvX190ZXN0X18vZW50aXRpZXMvcHVyZS1jbGFzc2VzLnRzIiwiLi4vc3JjL19fdGVzdF9fL2VudGl0aWVzL2FkZGl0aW9uYWwtdGVzdC1jbGFzc2VzLnRzIiwiLi4vc3JjL19fdGVzdF9fL3Rlc3RDYXNlcy9wdXJlLWNsYXNzZXMudGVzdC50cyIsIi4uL25vZGVfbW9kdWxlcy8ucG5wbS9Acm9sbHVwK3BsdWdpbi10eXBlc2NyaXB0QDEyLjEuNF9yb2xsdXBANC40Ni4yX3RzbGliQDIuOC4xX3R5cGVzY3JpcHRANS4wLjIvbm9kZV9tb2R1bGVzL3RzbGliL3RzbGliLmVzNi5qcyIsIi4uL3NyYy9fX3Rlc3RfXy9lbnRpdGllcy9kZWNvcmF0ZWQtY2xhc3Nlcy50cyIsIi4uL3NyYy9fX3Rlc3RfXy90ZXN0Q2FzZXMvZGVjb3JhdGVkLWNsYXNzZXMudGVzdC50cyIsIi4uL3NyYy9fX3Rlc3RfXy9lbnRpdGllcy9uZXN0ZWQtY2xhc3Nlcy50cyIsIi4uL3NyYy9fX3Rlc3RfXy90ZXN0Q2FzZXMvbmVzdGVkLWNsYXNzZXMudGVzdC50cyJdLCJzb3VyY2VzQ29udGVudCI6W251bGwsbnVsbCxudWxsLG51bGwsbnVsbCwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5Db3B5cmlnaHQgKGMpIE1pY3Jvc29mdCBDb3Jwb3JhdGlvbi5cclxuXHJcblBlcm1pc3Npb24gdG8gdXNlLCBjb3B5LCBtb2RpZnksIGFuZC9vciBkaXN0cmlidXRlIHRoaXMgc29mdHdhcmUgZm9yIGFueVxyXG5wdXJwb3NlIHdpdGggb3Igd2l0aG91dCBmZWUgaXMgaGVyZWJ5IGdyYW50ZWQuXHJcblxyXG5USEUgU09GVFdBUkUgSVMgUFJPVklERUQgXCJBUyBJU1wiIEFORCBUSEUgQVVUSE9SIERJU0NMQUlNUyBBTEwgV0FSUkFOVElFUyBXSVRIXHJcblJFR0FSRCBUTyBUSElTIFNPRlRXQVJFIElOQ0xVRElORyBBTEwgSU1QTElFRCBXQVJSQU5USUVTIE9GIE1FUkNIQU5UQUJJTElUWVxyXG5BTkQgRklUTkVTUy4gSU4gTk8gRVZFTlQgU0hBTEwgVEhFIEFVVEhPUiBCRSBMSUFCTEUgRk9SIEFOWSBTUEVDSUFMLCBESVJFQ1QsXHJcbklORElSRUNULCBPUiBDT05TRVFVRU5USUFMIERBTUFHRVMgT1IgQU5ZIERBTUFHRVMgV0hBVFNPRVZFUiBSRVNVTFRJTkcgRlJPTVxyXG5MT1NTIE9GIFVTRSwgREFUQSBPUiBQUk9GSVRTLCBXSEVUSEVSIElOIEFOIEFDVElPTiBPRiBDT05UUkFDVCwgTkVHTElHRU5DRSBPUlxyXG5PVEhFUiBUT1JUSU9VUyBBQ1RJT04sIEFSSVNJTkcgT1VUIE9GIE9SIElOIENPTk5FQ1RJT04gV0lUSCBUSEUgVVNFIE9SXHJcblBFUkZPUk1BTkNFIE9GIFRISVMgU09GVFdBUkUuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqICovXHJcbi8qIGdsb2JhbCBSZWZsZWN0LCBQcm9taXNlLCBTdXBwcmVzc2VkRXJyb3IsIFN5bWJvbCwgSXRlcmF0b3IgKi9cclxuXHJcbnZhciBleHRlbmRTdGF0aWNzID0gZnVuY3Rpb24oZCwgYikge1xyXG4gICAgZXh0ZW5kU3RhdGljcyA9IE9iamVjdC5zZXRQcm90b3R5cGVPZiB8fFxyXG4gICAgICAgICh7IF9fcHJvdG9fXzogW10gfSBpbnN0YW5jZW9mIEFycmF5ICYmIGZ1bmN0aW9uIChkLCBiKSB7IGQuX19wcm90b19fID0gYjsgfSkgfHxcclxuICAgICAgICBmdW5jdGlvbiAoZCwgYikgeyBmb3IgKHZhciBwIGluIGIpIGlmIChPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwoYiwgcCkpIGRbcF0gPSBiW3BdOyB9O1xyXG4gICAgcmV0dXJuIGV4dGVuZFN0YXRpY3MoZCwgYik7XHJcbn07XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gX19leHRlbmRzKGQsIGIpIHtcclxuICAgIGlmICh0eXBlb2YgYiAhPT0gXCJmdW5jdGlvblwiICYmIGIgIT09IG51bGwpXHJcbiAgICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcihcIkNsYXNzIGV4dGVuZHMgdmFsdWUgXCIgKyBTdHJpbmcoYikgKyBcIiBpcyBub3QgYSBjb25zdHJ1Y3RvciBvciBudWxsXCIpO1xyXG4gICAgZXh0ZW5kU3RhdGljcyhkLCBiKTtcclxuICAgIGZ1bmN0aW9uIF9fKCkgeyB0aGlzLmNvbnN0cnVjdG9yID0gZDsgfVxyXG4gICAgZC5wcm90b3R5cGUgPSBiID09PSBudWxsID8gT2JqZWN0LmNyZWF0ZShiKSA6IChfXy5wcm90b3R5cGUgPSBiLnByb3RvdHlwZSwgbmV3IF9fKCkpO1xyXG59XHJcblxyXG5leHBvcnQgdmFyIF9fYXNzaWduID0gZnVuY3Rpb24oKSB7XHJcbiAgICBfX2Fzc2lnbiA9IE9iamVjdC5hc3NpZ24gfHwgZnVuY3Rpb24gX19hc3NpZ24odCkge1xyXG4gICAgICAgIGZvciAodmFyIHMsIGkgPSAxLCBuID0gYXJndW1lbnRzLmxlbmd0aDsgaSA8IG47IGkrKykge1xyXG4gICAgICAgICAgICBzID0gYXJndW1lbnRzW2ldO1xyXG4gICAgICAgICAgICBmb3IgKHZhciBwIGluIHMpIGlmIChPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwocywgcCkpIHRbcF0gPSBzW3BdO1xyXG4gICAgICAgIH1cclxuICAgICAgICByZXR1cm4gdDtcclxuICAgIH1cclxuICAgIHJldHVybiBfX2Fzc2lnbi5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xyXG59XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gX19yZXN0KHMsIGUpIHtcclxuICAgIHZhciB0ID0ge307XHJcbiAgICBmb3IgKHZhciBwIGluIHMpIGlmIChPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwocywgcCkgJiYgZS5pbmRleE9mKHApIDwgMClcclxuICAgICAgICB0W3BdID0gc1twXTtcclxuICAgIGlmIChzICE9IG51bGwgJiYgdHlwZW9mIE9iamVjdC5nZXRPd25Qcm9wZXJ0eVN5bWJvbHMgPT09IFwiZnVuY3Rpb25cIilcclxuICAgICAgICBmb3IgKHZhciBpID0gMCwgcCA9IE9iamVjdC5nZXRPd25Qcm9wZXJ0eVN5bWJvbHMocyk7IGkgPCBwLmxlbmd0aDsgaSsrKSB7XHJcbiAgICAgICAgICAgIGlmIChlLmluZGV4T2YocFtpXSkgPCAwICYmIE9iamVjdC5wcm90b3R5cGUucHJvcGVydHlJc0VudW1lcmFibGUuY2FsbChzLCBwW2ldKSlcclxuICAgICAgICAgICAgICAgIHRbcFtpXV0gPSBzW3BbaV1dO1xyXG4gICAgICAgIH1cclxuICAgIHJldHVybiB0O1xyXG59XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gX19kZWNvcmF0ZShkZWNvcmF0b3JzLCB0YXJnZXQsIGtleSwgZGVzYykge1xyXG4gICAgdmFyIGMgPSBhcmd1bWVudHMubGVuZ3RoLCByID0gYyA8IDMgPyB0YXJnZXQgOiBkZXNjID09PSBudWxsID8gZGVzYyA9IE9iamVjdC5nZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3IodGFyZ2V0LCBrZXkpIDogZGVzYywgZDtcclxuICAgIGlmICh0eXBlb2YgUmVmbGVjdCA9PT0gXCJvYmplY3RcIiAmJiB0eXBlb2YgUmVmbGVjdC5kZWNvcmF0ZSA9PT0gXCJmdW5jdGlvblwiKSByID0gUmVmbGVjdC5kZWNvcmF0ZShkZWNvcmF0b3JzLCB0YXJnZXQsIGtleSwgZGVzYyk7XHJcbiAgICBlbHNlIGZvciAodmFyIGkgPSBkZWNvcmF0b3JzLmxlbmd0aCAtIDE7IGkgPj0gMDsgaS0tKSBpZiAoZCA9IGRlY29yYXRvcnNbaV0pIHIgPSAoYyA8IDMgPyBkKHIpIDogYyA+IDMgPyBkKHRhcmdldCwga2V5LCByKSA6IGQodGFyZ2V0LCBrZXkpKSB8fCByO1xyXG4gICAgcmV0dXJuIGMgPiAzICYmIHIgJiYgT2JqZWN0LmRlZmluZVByb3BlcnR5KHRhcmdldCwga2V5LCByKSwgcjtcclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIF9fcGFyYW0ocGFyYW1JbmRleCwgZGVjb3JhdG9yKSB7XHJcbiAgICByZXR1cm4gZnVuY3Rpb24gKHRhcmdldCwga2V5KSB7IGRlY29yYXRvcih0YXJnZXQsIGtleSwgcGFyYW1JbmRleCk7IH1cclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIF9fZXNEZWNvcmF0ZShjdG9yLCBkZXNjcmlwdG9ySW4sIGRlY29yYXRvcnMsIGNvbnRleHRJbiwgaW5pdGlhbGl6ZXJzLCBleHRyYUluaXRpYWxpemVycykge1xyXG4gICAgZnVuY3Rpb24gYWNjZXB0KGYpIHsgaWYgKGYgIT09IHZvaWQgMCAmJiB0eXBlb2YgZiAhPT0gXCJmdW5jdGlvblwiKSB0aHJvdyBuZXcgVHlwZUVycm9yKFwiRnVuY3Rpb24gZXhwZWN0ZWRcIik7IHJldHVybiBmOyB9XHJcbiAgICB2YXIga2luZCA9IGNvbnRleHRJbi5raW5kLCBrZXkgPSBraW5kID09PSBcImdldHRlclwiID8gXCJnZXRcIiA6IGtpbmQgPT09IFwic2V0dGVyXCIgPyBcInNldFwiIDogXCJ2YWx1ZVwiO1xyXG4gICAgdmFyIHRhcmdldCA9ICFkZXNjcmlwdG9ySW4gJiYgY3RvciA/IGNvbnRleHRJbltcInN0YXRpY1wiXSA/IGN0b3IgOiBjdG9yLnByb3RvdHlwZSA6IG51bGw7XHJcbiAgICB2YXIgZGVzY3JpcHRvciA9IGRlc2NyaXB0b3JJbiB8fCAodGFyZ2V0ID8gT2JqZWN0LmdldE93blByb3BlcnR5RGVzY3JpcHRvcih0YXJnZXQsIGNvbnRleHRJbi5uYW1lKSA6IHt9KTtcclxuICAgIHZhciBfLCBkb25lID0gZmFsc2U7XHJcbiAgICBmb3IgKHZhciBpID0gZGVjb3JhdG9ycy5sZW5ndGggLSAxOyBpID49IDA7IGktLSkge1xyXG4gICAgICAgIHZhciBjb250ZXh0ID0ge307XHJcbiAgICAgICAgZm9yICh2YXIgcCBpbiBjb250ZXh0SW4pIGNvbnRleHRbcF0gPSBwID09PSBcImFjY2Vzc1wiID8ge30gOiBjb250ZXh0SW5bcF07XHJcbiAgICAgICAgZm9yICh2YXIgcCBpbiBjb250ZXh0SW4uYWNjZXNzKSBjb250ZXh0LmFjY2Vzc1twXSA9IGNvbnRleHRJbi5hY2Nlc3NbcF07XHJcbiAgICAgICAgY29udGV4dC5hZGRJbml0aWFsaXplciA9IGZ1bmN0aW9uIChmKSB7IGlmIChkb25lKSB0aHJvdyBuZXcgVHlwZUVycm9yKFwiQ2Fubm90IGFkZCBpbml0aWFsaXplcnMgYWZ0ZXIgZGVjb3JhdGlvbiBoYXMgY29tcGxldGVkXCIpOyBleHRyYUluaXRpYWxpemVycy5wdXNoKGFjY2VwdChmIHx8IG51bGwpKTsgfTtcclxuICAgICAgICB2YXIgcmVzdWx0ID0gKDAsIGRlY29yYXRvcnNbaV0pKGtpbmQgPT09IFwiYWNjZXNzb3JcIiA/IHsgZ2V0OiBkZXNjcmlwdG9yLmdldCwgc2V0OiBkZXNjcmlwdG9yLnNldCB9IDogZGVzY3JpcHRvcltrZXldLCBjb250ZXh0KTtcclxuICAgICAgICBpZiAoa2luZCA9PT0gXCJhY2Nlc3NvclwiKSB7XHJcbiAgICAgICAgICAgIGlmIChyZXN1bHQgPT09IHZvaWQgMCkgY29udGludWU7XHJcbiAgICAgICAgICAgIGlmIChyZXN1bHQgPT09IG51bGwgfHwgdHlwZW9mIHJlc3VsdCAhPT0gXCJvYmplY3RcIikgdGhyb3cgbmV3IFR5cGVFcnJvcihcIk9iamVjdCBleHBlY3RlZFwiKTtcclxuICAgICAgICAgICAgaWYgKF8gPSBhY2NlcHQocmVzdWx0LmdldCkpIGRlc2NyaXB0b3IuZ2V0ID0gXztcclxuICAgICAgICAgICAgaWYgKF8gPSBhY2NlcHQocmVzdWx0LnNldCkpIGRlc2NyaXB0b3Iuc2V0ID0gXztcclxuICAgICAgICAgICAgaWYgKF8gPSBhY2NlcHQocmVzdWx0LmluaXQpKSBpbml0aWFsaXplcnMudW5zaGlmdChfKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgZWxzZSBpZiAoXyA9IGFjY2VwdChyZXN1bHQpKSB7XHJcbiAgICAgICAgICAgIGlmIChraW5kID09PSBcImZpZWxkXCIpIGluaXRpYWxpemVycy51bnNoaWZ0KF8pO1xyXG4gICAgICAgICAgICBlbHNlIGRlc2NyaXB0b3Jba2V5XSA9IF87XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG4gICAgaWYgKHRhcmdldCkgT2JqZWN0LmRlZmluZVByb3BlcnR5KHRhcmdldCwgY29udGV4dEluLm5hbWUsIGRlc2NyaXB0b3IpO1xyXG4gICAgZG9uZSA9IHRydWU7XHJcbn07XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gX19ydW5Jbml0aWFsaXplcnModGhpc0FyZywgaW5pdGlhbGl6ZXJzLCB2YWx1ZSkge1xyXG4gICAgdmFyIHVzZVZhbHVlID0gYXJndW1lbnRzLmxlbmd0aCA+IDI7XHJcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGluaXRpYWxpemVycy5sZW5ndGg7IGkrKykge1xyXG4gICAgICAgIHZhbHVlID0gdXNlVmFsdWUgPyBpbml0aWFsaXplcnNbaV0uY2FsbCh0aGlzQXJnLCB2YWx1ZSkgOiBpbml0aWFsaXplcnNbaV0uY2FsbCh0aGlzQXJnKTtcclxuICAgIH1cclxuICAgIHJldHVybiB1c2VWYWx1ZSA/IHZhbHVlIDogdm9pZCAwO1xyXG59O1xyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIF9fcHJvcEtleSh4KSB7XHJcbiAgICByZXR1cm4gdHlwZW9mIHggPT09IFwic3ltYm9sXCIgPyB4IDogXCJcIi5jb25jYXQoeCk7XHJcbn07XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gX19zZXRGdW5jdGlvbk5hbWUoZiwgbmFtZSwgcHJlZml4KSB7XHJcbiAgICBpZiAodHlwZW9mIG5hbWUgPT09IFwic3ltYm9sXCIpIG5hbWUgPSBuYW1lLmRlc2NyaXB0aW9uID8gXCJbXCIuY29uY2F0KG5hbWUuZGVzY3JpcHRpb24sIFwiXVwiKSA6IFwiXCI7XHJcbiAgICByZXR1cm4gT2JqZWN0LmRlZmluZVByb3BlcnR5KGYsIFwibmFtZVwiLCB7IGNvbmZpZ3VyYWJsZTogdHJ1ZSwgdmFsdWU6IHByZWZpeCA/IFwiXCIuY29uY2F0KHByZWZpeCwgXCIgXCIsIG5hbWUpIDogbmFtZSB9KTtcclxufTtcclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBfX21ldGFkYXRhKG1ldGFkYXRhS2V5LCBtZXRhZGF0YVZhbHVlKSB7XHJcbiAgICBpZiAodHlwZW9mIFJlZmxlY3QgPT09IFwib2JqZWN0XCIgJiYgdHlwZW9mIFJlZmxlY3QubWV0YWRhdGEgPT09IFwiZnVuY3Rpb25cIikgcmV0dXJuIFJlZmxlY3QubWV0YWRhdGEobWV0YWRhdGFLZXksIG1ldGFkYXRhVmFsdWUpO1xyXG59XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gX19hd2FpdGVyKHRoaXNBcmcsIF9hcmd1bWVudHMsIFAsIGdlbmVyYXRvcikge1xyXG4gICAgZnVuY3Rpb24gYWRvcHQodmFsdWUpIHsgcmV0dXJuIHZhbHVlIGluc3RhbmNlb2YgUCA/IHZhbHVlIDogbmV3IFAoZnVuY3Rpb24gKHJlc29sdmUpIHsgcmVzb2x2ZSh2YWx1ZSk7IH0pOyB9XHJcbiAgICByZXR1cm4gbmV3IChQIHx8IChQID0gUHJvbWlzZSkpKGZ1bmN0aW9uIChyZXNvbHZlLCByZWplY3QpIHtcclxuICAgICAgICBmdW5jdGlvbiBmdWxmaWxsZWQodmFsdWUpIHsgdHJ5IHsgc3RlcChnZW5lcmF0b3IubmV4dCh2YWx1ZSkpOyB9IGNhdGNoIChlKSB7IHJlamVjdChlKTsgfSB9XHJcbiAgICAgICAgZnVuY3Rpb24gcmVqZWN0ZWQodmFsdWUpIHsgdHJ5IHsgc3RlcChnZW5lcmF0b3JbXCJ0aHJvd1wiXSh2YWx1ZSkpOyB9IGNhdGNoIChlKSB7IHJlamVjdChlKTsgfSB9XHJcbiAgICAgICAgZnVuY3Rpb24gc3RlcChyZXN1bHQpIHsgcmVzdWx0LmRvbmUgPyByZXNvbHZlKHJlc3VsdC52YWx1ZSkgOiBhZG9wdChyZXN1bHQudmFsdWUpLnRoZW4oZnVsZmlsbGVkLCByZWplY3RlZCk7IH1cclxuICAgICAgICBzdGVwKChnZW5lcmF0b3IgPSBnZW5lcmF0b3IuYXBwbHkodGhpc0FyZywgX2FyZ3VtZW50cyB8fCBbXSkpLm5leHQoKSk7XHJcbiAgICB9KTtcclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIF9fZ2VuZXJhdG9yKHRoaXNBcmcsIGJvZHkpIHtcclxuICAgIHZhciBfID0geyBsYWJlbDogMCwgc2VudDogZnVuY3Rpb24oKSB7IGlmICh0WzBdICYgMSkgdGhyb3cgdFsxXTsgcmV0dXJuIHRbMV07IH0sIHRyeXM6IFtdLCBvcHM6IFtdIH0sIGYsIHksIHQsIGcgPSBPYmplY3QuY3JlYXRlKCh0eXBlb2YgSXRlcmF0b3IgPT09IFwiZnVuY3Rpb25cIiA/IEl0ZXJhdG9yIDogT2JqZWN0KS5wcm90b3R5cGUpO1xyXG4gICAgcmV0dXJuIGcubmV4dCA9IHZlcmIoMCksIGdbXCJ0aHJvd1wiXSA9IHZlcmIoMSksIGdbXCJyZXR1cm5cIl0gPSB2ZXJiKDIpLCB0eXBlb2YgU3ltYm9sID09PSBcImZ1bmN0aW9uXCIgJiYgKGdbU3ltYm9sLml0ZXJhdG9yXSA9IGZ1bmN0aW9uKCkgeyByZXR1cm4gdGhpczsgfSksIGc7XHJcbiAgICBmdW5jdGlvbiB2ZXJiKG4pIHsgcmV0dXJuIGZ1bmN0aW9uICh2KSB7IHJldHVybiBzdGVwKFtuLCB2XSk7IH07IH1cclxuICAgIGZ1bmN0aW9uIHN0ZXAob3ApIHtcclxuICAgICAgICBpZiAoZikgdGhyb3cgbmV3IFR5cGVFcnJvcihcIkdlbmVyYXRvciBpcyBhbHJlYWR5IGV4ZWN1dGluZy5cIik7XHJcbiAgICAgICAgd2hpbGUgKGcgJiYgKGcgPSAwLCBvcFswXSAmJiAoXyA9IDApKSwgXykgdHJ5IHtcclxuICAgICAgICAgICAgaWYgKGYgPSAxLCB5ICYmICh0ID0gb3BbMF0gJiAyID8geVtcInJldHVyblwiXSA6IG9wWzBdID8geVtcInRocm93XCJdIHx8ICgodCA9IHlbXCJyZXR1cm5cIl0pICYmIHQuY2FsbCh5KSwgMCkgOiB5Lm5leHQpICYmICEodCA9IHQuY2FsbCh5LCBvcFsxXSkpLmRvbmUpIHJldHVybiB0O1xyXG4gICAgICAgICAgICBpZiAoeSA9IDAsIHQpIG9wID0gW29wWzBdICYgMiwgdC52YWx1ZV07XHJcbiAgICAgICAgICAgIHN3aXRjaCAob3BbMF0pIHtcclxuICAgICAgICAgICAgICAgIGNhc2UgMDogY2FzZSAxOiB0ID0gb3A7IGJyZWFrO1xyXG4gICAgICAgICAgICAgICAgY2FzZSA0OiBfLmxhYmVsKys7IHJldHVybiB7IHZhbHVlOiBvcFsxXSwgZG9uZTogZmFsc2UgfTtcclxuICAgICAgICAgICAgICAgIGNhc2UgNTogXy5sYWJlbCsrOyB5ID0gb3BbMV07IG9wID0gWzBdOyBjb250aW51ZTtcclxuICAgICAgICAgICAgICAgIGNhc2UgNzogb3AgPSBfLm9wcy5wb3AoKTsgXy50cnlzLnBvcCgpOyBjb250aW51ZTtcclxuICAgICAgICAgICAgICAgIGRlZmF1bHQ6XHJcbiAgICAgICAgICAgICAgICAgICAgaWYgKCEodCA9IF8udHJ5cywgdCA9IHQubGVuZ3RoID4gMCAmJiB0W3QubGVuZ3RoIC0gMV0pICYmIChvcFswXSA9PT0gNiB8fCBvcFswXSA9PT0gMikpIHsgXyA9IDA7IGNvbnRpbnVlOyB9XHJcbiAgICAgICAgICAgICAgICAgICAgaWYgKG9wWzBdID09PSAzICYmICghdCB8fCAob3BbMV0gPiB0WzBdICYmIG9wWzFdIDwgdFszXSkpKSB7IF8ubGFiZWwgPSBvcFsxXTsgYnJlYWs7IH1cclxuICAgICAgICAgICAgICAgICAgICBpZiAob3BbMF0gPT09IDYgJiYgXy5sYWJlbCA8IHRbMV0pIHsgXy5sYWJlbCA9IHRbMV07IHQgPSBvcDsgYnJlYWs7IH1cclxuICAgICAgICAgICAgICAgICAgICBpZiAodCAmJiBfLmxhYmVsIDwgdFsyXSkgeyBfLmxhYmVsID0gdFsyXTsgXy5vcHMucHVzaChvcCk7IGJyZWFrOyB9XHJcbiAgICAgICAgICAgICAgICAgICAgaWYgKHRbMl0pIF8ub3BzLnBvcCgpO1xyXG4gICAgICAgICAgICAgICAgICAgIF8udHJ5cy5wb3AoKTsgY29udGludWU7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgb3AgPSBib2R5LmNhbGwodGhpc0FyZywgXyk7XHJcbiAgICAgICAgfSBjYXRjaCAoZSkgeyBvcCA9IFs2LCBlXTsgeSA9IDA7IH0gZmluYWxseSB7IGYgPSB0ID0gMDsgfVxyXG4gICAgICAgIGlmIChvcFswXSAmIDUpIHRocm93IG9wWzFdOyByZXR1cm4geyB2YWx1ZTogb3BbMF0gPyBvcFsxXSA6IHZvaWQgMCwgZG9uZTogdHJ1ZSB9O1xyXG4gICAgfVxyXG59XHJcblxyXG5leHBvcnQgdmFyIF9fY3JlYXRlQmluZGluZyA9IE9iamVjdC5jcmVhdGUgPyAoZnVuY3Rpb24obywgbSwgaywgazIpIHtcclxuICAgIGlmIChrMiA9PT0gdW5kZWZpbmVkKSBrMiA9IGs7XHJcbiAgICB2YXIgZGVzYyA9IE9iamVjdC5nZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3IobSwgayk7XHJcbiAgICBpZiAoIWRlc2MgfHwgKFwiZ2V0XCIgaW4gZGVzYyA/ICFtLl9fZXNNb2R1bGUgOiBkZXNjLndyaXRhYmxlIHx8IGRlc2MuY29uZmlndXJhYmxlKSkge1xyXG4gICAgICAgIGRlc2MgPSB7IGVudW1lcmFibGU6IHRydWUsIGdldDogZnVuY3Rpb24oKSB7IHJldHVybiBtW2tdOyB9IH07XHJcbiAgICB9XHJcbiAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkobywgazIsIGRlc2MpO1xyXG59KSA6IChmdW5jdGlvbihvLCBtLCBrLCBrMikge1xyXG4gICAgaWYgKGsyID09PSB1bmRlZmluZWQpIGsyID0gaztcclxuICAgIG9bazJdID0gbVtrXTtcclxufSk7XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gX19leHBvcnRTdGFyKG0sIG8pIHtcclxuICAgIGZvciAodmFyIHAgaW4gbSkgaWYgKHAgIT09IFwiZGVmYXVsdFwiICYmICFPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwobywgcCkpIF9fY3JlYXRlQmluZGluZyhvLCBtLCBwKTtcclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIF9fdmFsdWVzKG8pIHtcclxuICAgIHZhciBzID0gdHlwZW9mIFN5bWJvbCA9PT0gXCJmdW5jdGlvblwiICYmIFN5bWJvbC5pdGVyYXRvciwgbSA9IHMgJiYgb1tzXSwgaSA9IDA7XHJcbiAgICBpZiAobSkgcmV0dXJuIG0uY2FsbChvKTtcclxuICAgIGlmIChvICYmIHR5cGVvZiBvLmxlbmd0aCA9PT0gXCJudW1iZXJcIikgcmV0dXJuIHtcclxuICAgICAgICBuZXh0OiBmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICAgIGlmIChvICYmIGkgPj0gby5sZW5ndGgpIG8gPSB2b2lkIDA7XHJcbiAgICAgICAgICAgIHJldHVybiB7IHZhbHVlOiBvICYmIG9baSsrXSwgZG9uZTogIW8gfTtcclxuICAgICAgICB9XHJcbiAgICB9O1xyXG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcihzID8gXCJPYmplY3QgaXMgbm90IGl0ZXJhYmxlLlwiIDogXCJTeW1ib2wuaXRlcmF0b3IgaXMgbm90IGRlZmluZWQuXCIpO1xyXG59XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gX19yZWFkKG8sIG4pIHtcclxuICAgIHZhciBtID0gdHlwZW9mIFN5bWJvbCA9PT0gXCJmdW5jdGlvblwiICYmIG9bU3ltYm9sLml0ZXJhdG9yXTtcclxuICAgIGlmICghbSkgcmV0dXJuIG87XHJcbiAgICB2YXIgaSA9IG0uY2FsbChvKSwgciwgYXIgPSBbXSwgZTtcclxuICAgIHRyeSB7XHJcbiAgICAgICAgd2hpbGUgKChuID09PSB2b2lkIDAgfHwgbi0tID4gMCkgJiYgIShyID0gaS5uZXh0KCkpLmRvbmUpIGFyLnB1c2goci52YWx1ZSk7XHJcbiAgICB9XHJcbiAgICBjYXRjaCAoZXJyb3IpIHsgZSA9IHsgZXJyb3I6IGVycm9yIH07IH1cclxuICAgIGZpbmFsbHkge1xyXG4gICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgIGlmIChyICYmICFyLmRvbmUgJiYgKG0gPSBpW1wicmV0dXJuXCJdKSkgbS5jYWxsKGkpO1xyXG4gICAgICAgIH1cclxuICAgICAgICBmaW5hbGx5IHsgaWYgKGUpIHRocm93IGUuZXJyb3I7IH1cclxuICAgIH1cclxuICAgIHJldHVybiBhcjtcclxufVxyXG5cclxuLyoqIEBkZXByZWNhdGVkICovXHJcbmV4cG9ydCBmdW5jdGlvbiBfX3NwcmVhZCgpIHtcclxuICAgIGZvciAodmFyIGFyID0gW10sIGkgPSAwOyBpIDwgYXJndW1lbnRzLmxlbmd0aDsgaSsrKVxyXG4gICAgICAgIGFyID0gYXIuY29uY2F0KF9fcmVhZChhcmd1bWVudHNbaV0pKTtcclxuICAgIHJldHVybiBhcjtcclxufVxyXG5cclxuLyoqIEBkZXByZWNhdGVkICovXHJcbmV4cG9ydCBmdW5jdGlvbiBfX3NwcmVhZEFycmF5cygpIHtcclxuICAgIGZvciAodmFyIHMgPSAwLCBpID0gMCwgaWwgPSBhcmd1bWVudHMubGVuZ3RoOyBpIDwgaWw7IGkrKykgcyArPSBhcmd1bWVudHNbaV0ubGVuZ3RoO1xyXG4gICAgZm9yICh2YXIgciA9IEFycmF5KHMpLCBrID0gMCwgaSA9IDA7IGkgPCBpbDsgaSsrKVxyXG4gICAgICAgIGZvciAodmFyIGEgPSBhcmd1bWVudHNbaV0sIGogPSAwLCBqbCA9IGEubGVuZ3RoOyBqIDwgamw7IGorKywgaysrKVxyXG4gICAgICAgICAgICByW2tdID0gYVtqXTtcclxuICAgIHJldHVybiByO1xyXG59XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gX19zcHJlYWRBcnJheSh0bywgZnJvbSwgcGFjaykge1xyXG4gICAgaWYgKHBhY2sgfHwgYXJndW1lbnRzLmxlbmd0aCA9PT0gMikgZm9yICh2YXIgaSA9IDAsIGwgPSBmcm9tLmxlbmd0aCwgYXI7IGkgPCBsOyBpKyspIHtcclxuICAgICAgICBpZiAoYXIgfHwgIShpIGluIGZyb20pKSB7XHJcbiAgICAgICAgICAgIGlmICghYXIpIGFyID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoZnJvbSwgMCwgaSk7XHJcbiAgICAgICAgICAgIGFyW2ldID0gZnJvbVtpXTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcbiAgICByZXR1cm4gdG8uY29uY2F0KGFyIHx8IEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGZyb20pKTtcclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIF9fYXdhaXQodikge1xyXG4gICAgcmV0dXJuIHRoaXMgaW5zdGFuY2VvZiBfX2F3YWl0ID8gKHRoaXMudiA9IHYsIHRoaXMpIDogbmV3IF9fYXdhaXQodik7XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBfX2FzeW5jR2VuZXJhdG9yKHRoaXNBcmcsIF9hcmd1bWVudHMsIGdlbmVyYXRvcikge1xyXG4gICAgaWYgKCFTeW1ib2wuYXN5bmNJdGVyYXRvcikgdGhyb3cgbmV3IFR5cGVFcnJvcihcIlN5bWJvbC5hc3luY0l0ZXJhdG9yIGlzIG5vdCBkZWZpbmVkLlwiKTtcclxuICAgIHZhciBnID0gZ2VuZXJhdG9yLmFwcGx5KHRoaXNBcmcsIF9hcmd1bWVudHMgfHwgW10pLCBpLCBxID0gW107XHJcbiAgICByZXR1cm4gaSA9IE9iamVjdC5jcmVhdGUoKHR5cGVvZiBBc3luY0l0ZXJhdG9yID09PSBcImZ1bmN0aW9uXCIgPyBBc3luY0l0ZXJhdG9yIDogT2JqZWN0KS5wcm90b3R5cGUpLCB2ZXJiKFwibmV4dFwiKSwgdmVyYihcInRocm93XCIpLCB2ZXJiKFwicmV0dXJuXCIsIGF3YWl0UmV0dXJuKSwgaVtTeW1ib2wuYXN5bmNJdGVyYXRvcl0gPSBmdW5jdGlvbiAoKSB7IHJldHVybiB0aGlzOyB9LCBpO1xyXG4gICAgZnVuY3Rpb24gYXdhaXRSZXR1cm4oZikgeyByZXR1cm4gZnVuY3Rpb24gKHYpIHsgcmV0dXJuIFByb21pc2UucmVzb2x2ZSh2KS50aGVuKGYsIHJlamVjdCk7IH07IH1cclxuICAgIGZ1bmN0aW9uIHZlcmIobiwgZikgeyBpZiAoZ1tuXSkgeyBpW25dID0gZnVuY3Rpb24gKHYpIHsgcmV0dXJuIG5ldyBQcm9taXNlKGZ1bmN0aW9uIChhLCBiKSB7IHEucHVzaChbbiwgdiwgYSwgYl0pID4gMSB8fCByZXN1bWUobiwgdik7IH0pOyB9OyBpZiAoZikgaVtuXSA9IGYoaVtuXSk7IH0gfVxyXG4gICAgZnVuY3Rpb24gcmVzdW1lKG4sIHYpIHsgdHJ5IHsgc3RlcChnW25dKHYpKTsgfSBjYXRjaCAoZSkgeyBzZXR0bGUocVswXVszXSwgZSk7IH0gfVxyXG4gICAgZnVuY3Rpb24gc3RlcChyKSB7IHIudmFsdWUgaW5zdGFuY2VvZiBfX2F3YWl0ID8gUHJvbWlzZS5yZXNvbHZlKHIudmFsdWUudikudGhlbihmdWxmaWxsLCByZWplY3QpIDogc2V0dGxlKHFbMF1bMl0sIHIpOyB9XHJcbiAgICBmdW5jdGlvbiBmdWxmaWxsKHZhbHVlKSB7IHJlc3VtZShcIm5leHRcIiwgdmFsdWUpOyB9XHJcbiAgICBmdW5jdGlvbiByZWplY3QodmFsdWUpIHsgcmVzdW1lKFwidGhyb3dcIiwgdmFsdWUpOyB9XHJcbiAgICBmdW5jdGlvbiBzZXR0bGUoZiwgdikgeyBpZiAoZih2KSwgcS5zaGlmdCgpLCBxLmxlbmd0aCkgcmVzdW1lKHFbMF1bMF0sIHFbMF1bMV0pOyB9XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBfX2FzeW5jRGVsZWdhdG9yKG8pIHtcclxuICAgIHZhciBpLCBwO1xyXG4gICAgcmV0dXJuIGkgPSB7fSwgdmVyYihcIm5leHRcIiksIHZlcmIoXCJ0aHJvd1wiLCBmdW5jdGlvbiAoZSkgeyB0aHJvdyBlOyB9KSwgdmVyYihcInJldHVyblwiKSwgaVtTeW1ib2wuaXRlcmF0b3JdID0gZnVuY3Rpb24gKCkgeyByZXR1cm4gdGhpczsgfSwgaTtcclxuICAgIGZ1bmN0aW9uIHZlcmIobiwgZikgeyBpW25dID0gb1tuXSA/IGZ1bmN0aW9uICh2KSB7IHJldHVybiAocCA9ICFwKSA/IHsgdmFsdWU6IF9fYXdhaXQob1tuXSh2KSksIGRvbmU6IGZhbHNlIH0gOiBmID8gZih2KSA6IHY7IH0gOiBmOyB9XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBfX2FzeW5jVmFsdWVzKG8pIHtcclxuICAgIGlmICghU3ltYm9sLmFzeW5jSXRlcmF0b3IpIHRocm93IG5ldyBUeXBlRXJyb3IoXCJTeW1ib2wuYXN5bmNJdGVyYXRvciBpcyBub3QgZGVmaW5lZC5cIik7XHJcbiAgICB2YXIgbSA9IG9bU3ltYm9sLmFzeW5jSXRlcmF0b3JdLCBpO1xyXG4gICAgcmV0dXJuIG0gPyBtLmNhbGwobykgOiAobyA9IHR5cGVvZiBfX3ZhbHVlcyA9PT0gXCJmdW5jdGlvblwiID8gX192YWx1ZXMobykgOiBvW1N5bWJvbC5pdGVyYXRvcl0oKSwgaSA9IHt9LCB2ZXJiKFwibmV4dFwiKSwgdmVyYihcInRocm93XCIpLCB2ZXJiKFwicmV0dXJuXCIpLCBpW1N5bWJvbC5hc3luY0l0ZXJhdG9yXSA9IGZ1bmN0aW9uICgpIHsgcmV0dXJuIHRoaXM7IH0sIGkpO1xyXG4gICAgZnVuY3Rpb24gdmVyYihuKSB7IGlbbl0gPSBvW25dICYmIGZ1bmN0aW9uICh2KSB7IHJldHVybiBuZXcgUHJvbWlzZShmdW5jdGlvbiAocmVzb2x2ZSwgcmVqZWN0KSB7IHYgPSBvW25dKHYpLCBzZXR0bGUocmVzb2x2ZSwgcmVqZWN0LCB2LmRvbmUsIHYudmFsdWUpOyB9KTsgfTsgfVxyXG4gICAgZnVuY3Rpb24gc2V0dGxlKHJlc29sdmUsIHJlamVjdCwgZCwgdikgeyBQcm9taXNlLnJlc29sdmUodikudGhlbihmdW5jdGlvbih2KSB7IHJlc29sdmUoeyB2YWx1ZTogdiwgZG9uZTogZCB9KTsgfSwgcmVqZWN0KTsgfVxyXG59XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gX19tYWtlVGVtcGxhdGVPYmplY3QoY29va2VkLCByYXcpIHtcclxuICAgIGlmIChPYmplY3QuZGVmaW5lUHJvcGVydHkpIHsgT2JqZWN0LmRlZmluZVByb3BlcnR5KGNvb2tlZCwgXCJyYXdcIiwgeyB2YWx1ZTogcmF3IH0pOyB9IGVsc2UgeyBjb29rZWQucmF3ID0gcmF3OyB9XHJcbiAgICByZXR1cm4gY29va2VkO1xyXG59O1xyXG5cclxudmFyIF9fc2V0TW9kdWxlRGVmYXVsdCA9IE9iamVjdC5jcmVhdGUgPyAoZnVuY3Rpb24obywgdikge1xyXG4gICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KG8sIFwiZGVmYXVsdFwiLCB7IGVudW1lcmFibGU6IHRydWUsIHZhbHVlOiB2IH0pO1xyXG59KSA6IGZ1bmN0aW9uKG8sIHYpIHtcclxuICAgIG9bXCJkZWZhdWx0XCJdID0gdjtcclxufTtcclxuXHJcbnZhciBvd25LZXlzID0gZnVuY3Rpb24obykge1xyXG4gICAgb3duS2V5cyA9IE9iamVjdC5nZXRPd25Qcm9wZXJ0eU5hbWVzIHx8IGZ1bmN0aW9uIChvKSB7XHJcbiAgICAgICAgdmFyIGFyID0gW107XHJcbiAgICAgICAgZm9yICh2YXIgayBpbiBvKSBpZiAoT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG8sIGspKSBhclthci5sZW5ndGhdID0gaztcclxuICAgICAgICByZXR1cm4gYXI7XHJcbiAgICB9O1xyXG4gICAgcmV0dXJuIG93bktleXMobyk7XHJcbn07XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gX19pbXBvcnRTdGFyKG1vZCkge1xyXG4gICAgaWYgKG1vZCAmJiBtb2QuX19lc01vZHVsZSkgcmV0dXJuIG1vZDtcclxuICAgIHZhciByZXN1bHQgPSB7fTtcclxuICAgIGlmIChtb2QgIT0gbnVsbCkgZm9yICh2YXIgayA9IG93bktleXMobW9kKSwgaSA9IDA7IGkgPCBrLmxlbmd0aDsgaSsrKSBpZiAoa1tpXSAhPT0gXCJkZWZhdWx0XCIpIF9fY3JlYXRlQmluZGluZyhyZXN1bHQsIG1vZCwga1tpXSk7XHJcbiAgICBfX3NldE1vZHVsZURlZmF1bHQocmVzdWx0LCBtb2QpO1xyXG4gICAgcmV0dXJuIHJlc3VsdDtcclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIF9faW1wb3J0RGVmYXVsdChtb2QpIHtcclxuICAgIHJldHVybiAobW9kICYmIG1vZC5fX2VzTW9kdWxlKSA/IG1vZCA6IHsgZGVmYXVsdDogbW9kIH07XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBfX2NsYXNzUHJpdmF0ZUZpZWxkR2V0KHJlY2VpdmVyLCBzdGF0ZSwga2luZCwgZikge1xyXG4gICAgaWYgKGtpbmQgPT09IFwiYVwiICYmICFmKSB0aHJvdyBuZXcgVHlwZUVycm9yKFwiUHJpdmF0ZSBhY2Nlc3NvciB3YXMgZGVmaW5lZCB3aXRob3V0IGEgZ2V0dGVyXCIpO1xyXG4gICAgaWYgKHR5cGVvZiBzdGF0ZSA9PT0gXCJmdW5jdGlvblwiID8gcmVjZWl2ZXIgIT09IHN0YXRlIHx8ICFmIDogIXN0YXRlLmhhcyhyZWNlaXZlcikpIHRocm93IG5ldyBUeXBlRXJyb3IoXCJDYW5ub3QgcmVhZCBwcml2YXRlIG1lbWJlciBmcm9tIGFuIG9iamVjdCB3aG9zZSBjbGFzcyBkaWQgbm90IGRlY2xhcmUgaXRcIik7XHJcbiAgICByZXR1cm4ga2luZCA9PT0gXCJtXCIgPyBmIDoga2luZCA9PT0gXCJhXCIgPyBmLmNhbGwocmVjZWl2ZXIpIDogZiA/IGYudmFsdWUgOiBzdGF0ZS5nZXQocmVjZWl2ZXIpO1xyXG59XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gX19jbGFzc1ByaXZhdGVGaWVsZFNldChyZWNlaXZlciwgc3RhdGUsIHZhbHVlLCBraW5kLCBmKSB7XHJcbiAgICBpZiAoa2luZCA9PT0gXCJtXCIpIHRocm93IG5ldyBUeXBlRXJyb3IoXCJQcml2YXRlIG1ldGhvZCBpcyBub3Qgd3JpdGFibGVcIik7XHJcbiAgICBpZiAoa2luZCA9PT0gXCJhXCIgJiYgIWYpIHRocm93IG5ldyBUeXBlRXJyb3IoXCJQcml2YXRlIGFjY2Vzc29yIHdhcyBkZWZpbmVkIHdpdGhvdXQgYSBzZXR0ZXJcIik7XHJcbiAgICBpZiAodHlwZW9mIHN0YXRlID09PSBcImZ1bmN0aW9uXCIgPyByZWNlaXZlciAhPT0gc3RhdGUgfHwgIWYgOiAhc3RhdGUuaGFzKHJlY2VpdmVyKSkgdGhyb3cgbmV3IFR5cGVFcnJvcihcIkNhbm5vdCB3cml0ZSBwcml2YXRlIG1lbWJlciB0byBhbiBvYmplY3Qgd2hvc2UgY2xhc3MgZGlkIG5vdCBkZWNsYXJlIGl0XCIpO1xyXG4gICAgcmV0dXJuIChraW5kID09PSBcImFcIiA/IGYuY2FsbChyZWNlaXZlciwgdmFsdWUpIDogZiA/IGYudmFsdWUgPSB2YWx1ZSA6IHN0YXRlLnNldChyZWNlaXZlciwgdmFsdWUpKSwgdmFsdWU7XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBfX2NsYXNzUHJpdmF0ZUZpZWxkSW4oc3RhdGUsIHJlY2VpdmVyKSB7XHJcbiAgICBpZiAocmVjZWl2ZXIgPT09IG51bGwgfHwgKHR5cGVvZiByZWNlaXZlciAhPT0gXCJvYmplY3RcIiAmJiB0eXBlb2YgcmVjZWl2ZXIgIT09IFwiZnVuY3Rpb25cIikpIHRocm93IG5ldyBUeXBlRXJyb3IoXCJDYW5ub3QgdXNlICdpbicgb3BlcmF0b3Igb24gbm9uLW9iamVjdFwiKTtcclxuICAgIHJldHVybiB0eXBlb2Ygc3RhdGUgPT09IFwiZnVuY3Rpb25cIiA/IHJlY2VpdmVyID09PSBzdGF0ZSA6IHN0YXRlLmhhcyhyZWNlaXZlcik7XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBfX2FkZERpc3Bvc2FibGVSZXNvdXJjZShlbnYsIHZhbHVlLCBhc3luYykge1xyXG4gICAgaWYgKHZhbHVlICE9PSBudWxsICYmIHZhbHVlICE9PSB2b2lkIDApIHtcclxuICAgICAgICBpZiAodHlwZW9mIHZhbHVlICE9PSBcIm9iamVjdFwiICYmIHR5cGVvZiB2YWx1ZSAhPT0gXCJmdW5jdGlvblwiKSB0aHJvdyBuZXcgVHlwZUVycm9yKFwiT2JqZWN0IGV4cGVjdGVkLlwiKTtcclxuICAgICAgICB2YXIgZGlzcG9zZSwgaW5uZXI7XHJcbiAgICAgICAgaWYgKGFzeW5jKSB7XHJcbiAgICAgICAgICAgIGlmICghU3ltYm9sLmFzeW5jRGlzcG9zZSkgdGhyb3cgbmV3IFR5cGVFcnJvcihcIlN5bWJvbC5hc3luY0Rpc3Bvc2UgaXMgbm90IGRlZmluZWQuXCIpO1xyXG4gICAgICAgICAgICBkaXNwb3NlID0gdmFsdWVbU3ltYm9sLmFzeW5jRGlzcG9zZV07XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGlmIChkaXNwb3NlID09PSB2b2lkIDApIHtcclxuICAgICAgICAgICAgaWYgKCFTeW1ib2wuZGlzcG9zZSkgdGhyb3cgbmV3IFR5cGVFcnJvcihcIlN5bWJvbC5kaXNwb3NlIGlzIG5vdCBkZWZpbmVkLlwiKTtcclxuICAgICAgICAgICAgZGlzcG9zZSA9IHZhbHVlW1N5bWJvbC5kaXNwb3NlXTtcclxuICAgICAgICAgICAgaWYgKGFzeW5jKSBpbm5lciA9IGRpc3Bvc2U7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGlmICh0eXBlb2YgZGlzcG9zZSAhPT0gXCJmdW5jdGlvblwiKSB0aHJvdyBuZXcgVHlwZUVycm9yKFwiT2JqZWN0IG5vdCBkaXNwb3NhYmxlLlwiKTtcclxuICAgICAgICBpZiAoaW5uZXIpIGRpc3Bvc2UgPSBmdW5jdGlvbigpIHsgdHJ5IHsgaW5uZXIuY2FsbCh0aGlzKTsgfSBjYXRjaCAoZSkgeyByZXR1cm4gUHJvbWlzZS5yZWplY3QoZSk7IH0gfTtcclxuICAgICAgICBlbnYuc3RhY2sucHVzaCh7IHZhbHVlOiB2YWx1ZSwgZGlzcG9zZTogZGlzcG9zZSwgYXN5bmM6IGFzeW5jIH0pO1xyXG4gICAgfVxyXG4gICAgZWxzZSBpZiAoYXN5bmMpIHtcclxuICAgICAgICBlbnYuc3RhY2sucHVzaCh7IGFzeW5jOiB0cnVlIH0pO1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIHZhbHVlO1xyXG5cclxufVxyXG5cclxudmFyIF9TdXBwcmVzc2VkRXJyb3IgPSB0eXBlb2YgU3VwcHJlc3NlZEVycm9yID09PSBcImZ1bmN0aW9uXCIgPyBTdXBwcmVzc2VkRXJyb3IgOiBmdW5jdGlvbiAoZXJyb3IsIHN1cHByZXNzZWQsIG1lc3NhZ2UpIHtcclxuICAgIHZhciBlID0gbmV3IEVycm9yKG1lc3NhZ2UpO1xyXG4gICAgcmV0dXJuIGUubmFtZSA9IFwiU3VwcHJlc3NlZEVycm9yXCIsIGUuZXJyb3IgPSBlcnJvciwgZS5zdXBwcmVzc2VkID0gc3VwcHJlc3NlZCwgZTtcclxufTtcclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBfX2Rpc3Bvc2VSZXNvdXJjZXMoZW52KSB7XHJcbiAgICBmdW5jdGlvbiBmYWlsKGUpIHtcclxuICAgICAgICBlbnYuZXJyb3IgPSBlbnYuaGFzRXJyb3IgPyBuZXcgX1N1cHByZXNzZWRFcnJvcihlLCBlbnYuZXJyb3IsIFwiQW4gZXJyb3Igd2FzIHN1cHByZXNzZWQgZHVyaW5nIGRpc3Bvc2FsLlwiKSA6IGU7XHJcbiAgICAgICAgZW52Lmhhc0Vycm9yID0gdHJ1ZTtcclxuICAgIH1cclxuICAgIHZhciByLCBzID0gMDtcclxuICAgIGZ1bmN0aW9uIG5leHQoKSB7XHJcbiAgICAgICAgd2hpbGUgKHIgPSBlbnYuc3RhY2sucG9wKCkpIHtcclxuICAgICAgICAgICAgdHJ5IHtcclxuICAgICAgICAgICAgICAgIGlmICghci5hc3luYyAmJiBzID09PSAxKSByZXR1cm4gcyA9IDAsIGVudi5zdGFjay5wdXNoKHIpLCBQcm9taXNlLnJlc29sdmUoKS50aGVuKG5leHQpO1xyXG4gICAgICAgICAgICAgICAgaWYgKHIuZGlzcG9zZSkge1xyXG4gICAgICAgICAgICAgICAgICAgIHZhciByZXN1bHQgPSByLmRpc3Bvc2UuY2FsbChyLnZhbHVlKTtcclxuICAgICAgICAgICAgICAgICAgICBpZiAoci5hc3luYykgcmV0dXJuIHMgfD0gMiwgUHJvbWlzZS5yZXNvbHZlKHJlc3VsdCkudGhlbihuZXh0LCBmdW5jdGlvbihlKSB7IGZhaWwoZSk7IHJldHVybiBuZXh0KCk7IH0pO1xyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgZWxzZSBzIHw9IDE7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgY2F0Y2ggKGUpIHtcclxuICAgICAgICAgICAgICAgIGZhaWwoZSk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgICAgaWYgKHMgPT09IDEpIHJldHVybiBlbnYuaGFzRXJyb3IgPyBQcm9taXNlLnJlamVjdChlbnYuZXJyb3IpIDogUHJvbWlzZS5yZXNvbHZlKCk7XHJcbiAgICAgICAgaWYgKGVudi5oYXNFcnJvcikgdGhyb3cgZW52LmVycm9yO1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIG5leHQoKTtcclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIF9fcmV3cml0ZVJlbGF0aXZlSW1wb3J0RXh0ZW5zaW9uKHBhdGgsIHByZXNlcnZlSnN4KSB7XHJcbiAgICBpZiAodHlwZW9mIHBhdGggPT09IFwic3RyaW5nXCIgJiYgL15cXC5cXC4/XFwvLy50ZXN0KHBhdGgpKSB7XHJcbiAgICAgICAgcmV0dXJuIHBhdGgucmVwbGFjZSgvXFwuKHRzeCkkfCgoPzpcXC5kKT8pKCg/OlxcLlteLi9dKz8pPylcXC4oW2NtXT8pdHMkL2ksIGZ1bmN0aW9uIChtLCB0c3gsIGQsIGV4dCwgY20pIHtcclxuICAgICAgICAgICAgcmV0dXJuIHRzeCA/IHByZXNlcnZlSnN4ID8gXCIuanN4XCIgOiBcIi5qc1wiIDogZCAmJiAoIWV4dCB8fCAhY20pID8gbSA6IChkICsgZXh0ICsgXCIuXCIgKyBjbS50b0xvd2VyQ2FzZSgpICsgXCJqc1wiKTtcclxuICAgICAgICB9KTtcclxuICAgIH1cclxuICAgIHJldHVybiBwYXRoO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgICBfX2V4dGVuZHM6IF9fZXh0ZW5kcyxcclxuICAgIF9fYXNzaWduOiBfX2Fzc2lnbixcclxuICAgIF9fcmVzdDogX19yZXN0LFxyXG4gICAgX19kZWNvcmF0ZTogX19kZWNvcmF0ZSxcclxuICAgIF9fcGFyYW06IF9fcGFyYW0sXHJcbiAgICBfX2VzRGVjb3JhdGU6IF9fZXNEZWNvcmF0ZSxcclxuICAgIF9fcnVuSW5pdGlhbGl6ZXJzOiBfX3J1bkluaXRpYWxpemVycyxcclxuICAgIF9fcHJvcEtleTogX19wcm9wS2V5LFxyXG4gICAgX19zZXRGdW5jdGlvbk5hbWU6IF9fc2V0RnVuY3Rpb25OYW1lLFxyXG4gICAgX19tZXRhZGF0YTogX19tZXRhZGF0YSxcclxuICAgIF9fYXdhaXRlcjogX19hd2FpdGVyLFxyXG4gICAgX19nZW5lcmF0b3I6IF9fZ2VuZXJhdG9yLFxyXG4gICAgX19jcmVhdGVCaW5kaW5nOiBfX2NyZWF0ZUJpbmRpbmcsXHJcbiAgICBfX2V4cG9ydFN0YXI6IF9fZXhwb3J0U3RhcixcclxuICAgIF9fdmFsdWVzOiBfX3ZhbHVlcyxcclxuICAgIF9fcmVhZDogX19yZWFkLFxyXG4gICAgX19zcHJlYWQ6IF9fc3ByZWFkLFxyXG4gICAgX19zcHJlYWRBcnJheXM6IF9fc3ByZWFkQXJyYXlzLFxyXG4gICAgX19zcHJlYWRBcnJheTogX19zcHJlYWRBcnJheSxcclxuICAgIF9fYXdhaXQ6IF9fYXdhaXQsXHJcbiAgICBfX2FzeW5jR2VuZXJhdG9yOiBfX2FzeW5jR2VuZXJhdG9yLFxyXG4gICAgX19hc3luY0RlbGVnYXRvcjogX19hc3luY0RlbGVnYXRvcixcclxuICAgIF9fYXN5bmNWYWx1ZXM6IF9fYXN5bmNWYWx1ZXMsXHJcbiAgICBfX21ha2VUZW1wbGF0ZU9iamVjdDogX19tYWtlVGVtcGxhdGVPYmplY3QsXHJcbiAgICBfX2ltcG9ydFN0YXI6IF9faW1wb3J0U3RhcixcclxuICAgIF9faW1wb3J0RGVmYXVsdDogX19pbXBvcnREZWZhdWx0LFxyXG4gICAgX19jbGFzc1ByaXZhdGVGaWVsZEdldDogX19jbGFzc1ByaXZhdGVGaWVsZEdldCxcclxuICAgIF9fY2xhc3NQcml2YXRlRmllbGRTZXQ6IF9fY2xhc3NQcml2YXRlRmllbGRTZXQsXHJcbiAgICBfX2NsYXNzUHJpdmF0ZUZpZWxkSW46IF9fY2xhc3NQcml2YXRlRmllbGRJbixcclxuICAgIF9fYWRkRGlzcG9zYWJsZVJlc291cmNlOiBfX2FkZERpc3Bvc2FibGVSZXNvdXJjZSxcclxuICAgIF9fZGlzcG9zZVJlc291cmNlczogX19kaXNwb3NlUmVzb3VyY2VzLFxyXG4gICAgX19yZXdyaXRlUmVsYXRpdmVJbXBvcnRFeHRlbnNpb246IF9fcmV3cml0ZVJlbGF0aXZlSW1wb3J0RXh0ZW5zaW9uLFxyXG59O1xyXG4iLG51bGwsbnVsbCxudWxsLG51bGxdLCJuYW1lcyI6WyJkZXNjcmliZSIsInRlc3QiLCJJc1N0cmluZyIsIkxlbmd0aCIsIk1hdGNoZXMiLCJJc051bWJlciIsIklzUG9zaXRpdmUiLCJJc0VtYWlsIiwiTWluIiwiTWF4IiwiSXNFbnVtIiwiSXNCb29sZWFuIiwiSXNPcHRpb25hbCIsIklzQXJyYXkiLCJWYWxpZGF0ZU5lc3RlZCIsIklzRGF0ZSJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7QUFXQSxNQUFNLHNCQUFzQixHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLEdBQUcsRUFBRSxFQUFFLGVBQWUsQ0FBQztBQUUzRSxNQUFNLFlBQVksR0FBRztJQUNuQixNQUFNLEVBQUUsRUFBRSxJQUFJLEVBQUUsUUFBUSxFQUFFLEtBQUssRUFBRSxRQUFRLEVBQUU7SUFDM0MsR0FBRyxFQUFFLEVBQUUsSUFBSSxFQUFFLEtBQXNCLENBQUU7SUFDckMsT0FBTyxFQUFFLEVBQUUsSUFBSSxFQUFFLFNBQTBCLENBQUU7QUFDN0MsSUFBQSxNQUFNLEVBQUUsRUFBRSxJQUFJLEVBQUUsUUFBUSxFQUFFLEtBQUssRUFBRSxRQUFRLEVBQUUsTUFBTSxFQUFFLFFBQVEsRUFBRTtJQUM3RCxPQUFPLEVBQUUsRUFBRSxJQUFJLEVBQUUsU0FBUyxFQUFFLEtBQUssRUFBRSxTQUFTLEVBQUU7SUFDOUMsTUFBTSxFQUFFLEVBQUUsSUFBSSxFQUFFLFFBQVEsRUFBRSxLQUFLLEVBQUUsUUFBUSxFQUFFO0FBQzNDLElBQUEsTUFBTSxFQUFFLEVBQUUsSUFBSSxFQUFFLFFBQVEsRUFBRSxLQUFLLEVBQUUsU0FBUyxFQUFFLE1BQU0sRUFBRSxPQUFPLEVBQUU7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Q0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQXNDQTtBQUNPLFNBQVMsVUFBVSxDQUFDLFVBQVUsRUFBRSxNQUFNLEVBQUUsR0FBRyxFQUFFLElBQUksRUFBRTtBQUMxRCxJQUFJLElBQUksQ0FBQyxHQUFHLFNBQVMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLEdBQUcsTUFBTSxHQUFHLElBQUksS0FBSyxJQUFJLEdBQUcsSUFBSSxHQUFHLE1BQU0sQ0FBQyx3QkFBd0IsQ0FBQyxNQUFNLEVBQUUsR0FBRyxDQUFDLEdBQUcsSUFBSSxFQUFFLENBQUMsQ0FBQztBQUNqSSxJQUFJLElBQUksT0FBTyxPQUFPLEtBQUssUUFBUSxJQUFJLE9BQU8sT0FBTyxDQUFDLFFBQVEsS0FBSyxVQUFVLEVBQUUsQ0FBQyxHQUFHLE9BQU8sQ0FBQyxRQUFRLENBQUMsVUFBVSxFQUFFLE1BQU0sRUFBRSxHQUFHLEVBQUUsSUFBSSxDQUFDLENBQUM7QUFDbkksU0FBUyxLQUFLLElBQUksQ0FBQyxHQUFHLFVBQVUsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUUsSUFBSSxDQUFDLEdBQUcsVUFBVSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDLE1BQU0sRUFBRSxHQUFHLEVBQUUsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLE1BQU0sRUFBRSxHQUFHLENBQUMsS0FBSyxDQUFDLENBQUM7QUFDdEosSUFBSSxPQUFPLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxJQUFJLE1BQU0sQ0FBQyxjQUFjLENBQUMsTUFBTSxFQUFFLEdBQUcsRUFBRSxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUM7QUFDbEUsQ0FBQztBQTRR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QUMsVUFBVSxDQUFDO0FBRTVCLFFBQUEsTUFBTSxDQUFDLFdBQVcsQ0FBQyxNQUFNLENBQUMsVUFBVSxDQUFDLEVBQUUsQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFDO0FBQ25ELFFBQUEsTUFBTSxDQUFDLFdBQVcsQ0FBQyxNQUFNLENBQUMsVUFBVSxDQUFDLEtBQUssQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFDOztBQUd0RCxRQUFBLE1BQU0sQ0FBQyxXQUFXLENBQUMsTUFBTSxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLENBQUMsQ0FBQztBQUN2RCxRQUFBLE1BQU0sQ0FBQyxXQUFXLENBQUMsTUFBTSxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLEdBQUcsQ0FBQztBQUV6RCxRQUFBLE1BQU0sQ0FBQyxXQUFXLENBQUMsTUFBTSxDQUFDLFVBQVUsQ0FBQyxXQUFXLENBQUMsU0FBUyxFQUFFLEVBQUUsQ0FBQztBQUMvRCxRQUFBLE1BQU0sQ0FBQyxXQUFXLENBQUMsTUFBTSxDQUFDLFVBQVUsQ0FBQyxXQUFXLENBQUMsU0FBUyxFQUFFLEdBQUcsQ0FBQztBQUVoRSxRQUFBLE1BQU0sQ0FBQyxXQUFXLENBQUMsTUFBTSxDQUFDLFVBQVUsQ0FBQyxRQUFRLENBQUMsU0FBUyxFQUFFLENBQUMsQ0FBQztBQUMzRCxRQUFBLE1BQU0sQ0FBQyxXQUFXLENBQUMsTUFBTSxDQUFDLFVBQVUsQ0FBQyxRQUFRLENBQUMsU0FBUyxFQUFFLEVBQUUsQ0FBQztBQUU1RCxRQUFBLE1BQU0sQ0FBQyxXQUFXLENBQUMsTUFBTSxDQUFDLFVBQVUsQ0FBQyxVQUFVLENBQUMsSUFBSSxFQUFFLE9BQU8sQ0FBQztBQUM5RCxRQUFBLE1BQU0sQ0FBQyxXQUFXLENBQUMsTUFBTSxDQUFDLFVBQVUsQ0FBQyxVQUFVLENBQUMsS0FBSyxDQUFDLElBQUksRUFBRSxRQUFRLENBQUM7QUFFckUsUUFBQSxNQUFNLENBQUMsV0FBVyxDQUFDLE1BQU0sQ0FBQyxVQUFVLENBQUMsT0FBTyxDQUFDLElBQUks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SSxFQUFFLFFBQVEsQ0FBQzs7QUFHL0QsUUFBQSxNQUFNLENBQUMsV0FBVyxDQUFDLE1BQU0sQ0FBQyxVQUFVLENBQUMsT0FBTyxDQUFDLElBQUksRUFBRSxPQUFPLENBQUM7QUFDM0QsUUFBQSxNQUFNLENBQUMsV0FBVyxDQUFDLE1BQU0sQ0FBQyxVQUFVLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxJQUFJLEVBQUUsUUFBUSxDQUFDO0FBQ3BFLElBQUEsQ0FBQyxDQUFDO0FBRUYsSUFBQUEsY0FBSSxDQUFDLDZDQUE2QyxFQUFFLE1BQUs7QUFDdkQsUUFBQSxNQUFNLE1BQU0sR0FBRyxTQUFTLENBQUMsVUFBVSxDQUFDO0FBQ3BDLFFBQUEsTUFBTSxNQUFNLEdBQUcsTUFBTSxDQUFDLE1BQU07UUFFNUIsTUFBTSxDQUFDLFdBQVcsQ0FBQyxNQUFNLENBQUMsSUFBSSxFQUFFLFFBQVEsQ0FBQztBQUN6QyxRQUFBLE1BQU0sQ0FBQyxFQUFFLENBQUMsTUFBTSxDQUFDLFVBQVUsQ0FBQzs7QUFHNUIsUUFBQSxNQUFNLENBQUMsV0FBVyxDQUFDLE1BQU0sQ0FBQyxVQUFVLENBQUMsU0FBUyxDQUFDLElBQUksRUFBRSxRQUFRLENBQUM7QUFDOUQsUUFBQSxNQUFNLENBQUMsV0FBVyxDQUFDLE1BQU0sQ0FBQyxVQUFVLENBQUMsU0FBUyxDQUFDLE1BQU0sRUFBRSxXQUFXLENBQUM7QUFDckUsSUFBQSxDQUFDLENBQUM7QUFFRixJQUFBQSxjQUFJLENBQUMsNkNBQTZDLEVBQUUsTUFBSztBQUN2RCxRQUFBLE1BQU0sTUFBTSxHQUFHLFNBQVMsQ0FBQyxVQUFVLENBQUM7QUFDcEMsUUFBQSxNQUFNLE1BQU0sR0FBRyxNQUFNLENBQUMsTUFBTTtRQUU1QixNQUFNLENBQUMsV0FBVyxDQUFDLE1BQU0sQ0FBQyxJQUFJLEVBQUUsUUFBUSxDQUFDO0FBQ3pDLFFBQUEsTUFBTSxDQUFDLEVBQUUsQ0FBQyxNQUFNLENBQUMsVUFBVSxDQUFDO0FBRTVCLFFBQUEsTUFBTSxDQUFDLFdBQVcsQ0FBQyxNQUFNLENBQUMsVUFBVSxDQUFDLEVBQUUsQ0FBQyxJQUFJLEVBQUUsUUFBUSxDQUFDO0FBQ3ZELFFBQUEsTUFBTSxDQUFDLFdBQVcsQ0FBQyxNQUFNLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsUUFBUSxDQUFDO0FBQ3pELFFBQUEsTUFBTSxDQUFDLFdBQVcsQ0FBQyxNQUFNLENBQUMsVUFBVSxDQUFDLE1BQU0sQ0FBQyxJQUFJLEVBQUUsUUFBUSxDQUFDO0FBQzdELElBQUEsQ0FBQyxDQUFDO0FBQ0osQ0FBQyxDQUFDOzsiLCJ4X2dvb2dsZV9pZ25vcmVMaXN0IjpbNV19
|