ts-class-to-openapi 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,329 @@
1
+ import { type SchemaType } from './types.js';
2
+ /**
3
+ * Configuration options for SchemaTransformer memory management
4
+ */
5
+ interface TransformerOptions {
6
+ /** Maximum number of schemas to cache before cleanup (default: 100) */
7
+ maxCacheSize?: number;
8
+ /** Whether to automatically clean up cache (default: true) */
9
+ autoCleanup?: boolean;
10
+ }
11
+ /**
12
+ * Transforms class-validator decorated classes into OpenAPI schema objects.
13
+ * Analyzes TypeScript source files directly using the TypeScript compiler API.
14
+ * Implemented as a singleton for performance optimization.
15
+ *
16
+ * @example
17
+ * ```typescript
18
+ * const transformer = SchemaTransformer.getInstance();
19
+ * const schema = transformer.transform(User);
20
+ * console.log(schema);
21
+ * ```
22
+ *
23
+ * @public
24
+ */
25
+ declare class SchemaTransformer {
26
+ /**
27
+ * Singleton instance
28
+ * @private
29
+ */
30
+ private static instance;
31
+ /**
32
+ * TypeScript program instance for analyzing source files.
33
+ * @private
34
+ */
35
+ private program;
36
+ /**
37
+ * TypeScript type checker for resolving types.
38
+ * @private
39
+ */
40
+ private checker;
41
+ /**
42
+ * Cache for storing transformed class schemas to avoid reprocessing.
43
+ * Key format: "fileName:className" for uniqueness across different files.
44
+ * @private
45
+ */
46
+ private classCache;
47
+ /**
48
+ * Maximum number of entries to keep in cache before cleanup
49
+ * @private
50
+ */
51
+ private readonly maxCacheSize;
52
+ /**
53
+ * Whether to automatically clean up cache
54
+ * @private
55
+ */
56
+ private readonly autoCleanup;
57
+ /**
58
+ * Set of file paths that have been loaded to avoid redundant processing
59
+ * @private
60
+ */
61
+ private loadedFiles;
62
+ /**
63
+ * Private constructor for singleton pattern.
64
+ *
65
+ * @param tsConfigPath - Optional path to a specific TypeScript config file
66
+ * @param options - Configuration options for memory management
67
+ * @throws {Error} When TypeScript configuration cannot be loaded
68
+ * @private
69
+ */
70
+ private constructor();
71
+ /**
72
+ * Generates a unique cache key using file name and class name.
73
+ *
74
+ * @param fileName - The source file name
75
+ * @param className - The class name
76
+ * @returns Unique cache key in format "fileName:className"
77
+ * @private
78
+ */
79
+ private getCacheKey;
80
+ /**
81
+ * Cleans up cache when it exceeds maximum size to prevent memory leaks.
82
+ * Removes oldest entries using LRU strategy.
83
+ * @private
84
+ */
85
+ private cleanupCache;
86
+ /**
87
+ * Gets relevant source files for a class, filtering out unnecessary files to save memory.
88
+ *
89
+ * @param className - The name of the class to find files for
90
+ * @param filePath - Optional specific file path
91
+ * @returns Array of relevant source files
92
+ * @private
93
+ */
94
+ private getRelevantSourceFiles;
95
+ /**
96
+ * Transforms a class by its name into an OpenAPI schema object.
97
+ *
98
+ * @param className - The name of the class to transform
99
+ * @param filePath - Optional path to the file containing the class
100
+ * @returns Object containing the class name and its corresponding JSON schema
101
+ * @throws {Error} When the specified class cannot be found
102
+ * @private
103
+ */
104
+ private transformByName;
105
+ /**
106
+ * Gets the singleton instance of SchemaTransformer.
107
+ *
108
+ * @param tsConfigPath - Optional path to a specific TypeScript config file (only used on first call)
109
+ * @param options - Configuration options for memory management (only used on first call)
110
+ * @returns The singleton instance
111
+ *
112
+ * @example
113
+ * ```typescript
114
+ * const transformer = SchemaTransformer.getInstance();
115
+ * ```
116
+ *
117
+ * @example
118
+ * ```typescript
119
+ * // With memory optimization options
120
+ * const transformer = SchemaTransformer.getInstance('./tsconfig.json', {
121
+ * maxCacheSize: 50,
122
+ * autoCleanup: true
123
+ * });
124
+ * ```
125
+ *
126
+ * @public
127
+ */
128
+ /**
129
+ * Clears the current singleton instance. Useful for testing or when you need
130
+ * to create a new instance with different configuration.
131
+ */
132
+ static clearInstance(): void;
133
+ static getInstance(tsConfigPath?: string, options?: TransformerOptions): SchemaTransformer;
134
+ /**
135
+ * Transforms a class constructor function into an OpenAPI schema object.
136
+ *
137
+ * @param cls - The class constructor function to transform
138
+ * @returns Object containing the class name and its corresponding JSON schema
139
+ *
140
+ * @example
141
+ * ```typescript
142
+ * import { User } from './entities/user.js';
143
+ * const transformer = SchemaTransformer.getInstance();
144
+ * const schema = transformer.transform(User);
145
+ * ```
146
+ *
147
+ * @public
148
+ */
149
+ transform(cls: Function): {
150
+ name: string;
151
+ schema: SchemaType;
152
+ };
153
+ /**
154
+ * Clears all cached schemas and loaded file references to free memory.
155
+ * Useful for long-running applications or when processing many different classes.
156
+ *
157
+ * @example
158
+ * ```typescript
159
+ * const transformer = SchemaTransformer.getInstance();
160
+ * // After processing many classes...
161
+ * transformer.clearCache();
162
+ * ```
163
+ *
164
+ * @public
165
+ */
166
+ clearCache(): void;
167
+ /**
168
+ * Gets memory usage statistics for monitoring and debugging.
169
+ *
170
+ * @returns Object containing cache size and loaded files count
171
+ *
172
+ * @example
173
+ * ```typescript
174
+ * const transformer = SchemaTransformer.getInstance();
175
+ * const stats = transformer.getMemoryStats();
176
+ * console.log(`Cache entries: ${stats.cacheSize}, Files loaded: ${stats.loadedFiles}`);
177
+ * ```
178
+ *
179
+ * @public
180
+ */
181
+ getMemoryStats(): {
182
+ cacheSize: number;
183
+ loadedFiles: number;
184
+ };
185
+ /**
186
+ * Finds a class declaration by name within a source file.
187
+ *
188
+ * @param sourceFile - The TypeScript source file to search in
189
+ * @param className - The name of the class to find
190
+ * @returns The class declaration node if found, undefined otherwise
191
+ * @private
192
+ */
193
+ private findClassByName;
194
+ /**
195
+ * Transforms a TypeScript class declaration into a schema object.
196
+ *
197
+ * @param classNode - The TypeScript class declaration node
198
+ * @returns Object containing class name and generated schema
199
+ * @private
200
+ */
201
+ private transformClass;
202
+ /**
203
+ * Extracts property information from a class declaration.
204
+ *
205
+ * @param classNode - The TypeScript class declaration node
206
+ * @returns Array of property information including names, types, decorators, and optional status
207
+ * @private
208
+ */
209
+ private extractProperties;
210
+ /**
211
+ * Gets the TypeScript type of a property as a string.
212
+ *
213
+ * @param property - The property declaration to analyze
214
+ * @returns String representation of the property's type
215
+ * @private
216
+ */
217
+ private getPropertyType;
218
+ /**
219
+ * Converts a TypeScript type node to its string representation.
220
+ *
221
+ * @param typeNode - The TypeScript type node to convert
222
+ * @returns String representation of the type
223
+ * @private
224
+ */
225
+ private getTypeNodeToString;
226
+ /**
227
+ * Extracts decorator information from a property declaration.
228
+ *
229
+ * @param member - The property declaration to analyze
230
+ * @returns Array of decorator information including names and arguments
231
+ * @private
232
+ */
233
+ private extractDecorators;
234
+ /**
235
+ * Gets the name of a decorator from a call expression.
236
+ *
237
+ * @param callExpression - The decorator call expression
238
+ * @returns The decorator name or "unknown" if not identifiable
239
+ * @private
240
+ */
241
+ private getDecoratorName;
242
+ /**
243
+ * Extracts arguments from a decorator call expression.
244
+ *
245
+ * @param callExpression - The decorator call expression
246
+ * @returns Array of parsed decorator arguments
247
+ * @private
248
+ */
249
+ private getDecoratorArguments;
250
+ /**
251
+ * Generates an OpenAPI schema from extracted property information.
252
+ *
253
+ * @param properties - Array of property information to process
254
+ * @returns Complete OpenAPI schema object with properties and validation rules
255
+ * @private
256
+ */
257
+ private generateSchema;
258
+ /**
259
+ * Maps TypeScript types to OpenAPI schema types and formats.
260
+ * Handles primitive types, arrays, and nested objects recursively.
261
+ *
262
+ * @param type - The TypeScript type string to map
263
+ * @returns Object containing OpenAPI type, optional format, and nested schema
264
+ * @private
265
+ */
266
+ private mapTypeToSchema;
267
+ /**
268
+ * Applies class-validator decorators to schema properties.
269
+ * Maps validation decorators to their corresponding OpenAPI schema constraints.
270
+ *
271
+ * @param decorators - Array of decorator information to apply
272
+ * @param schema - The schema object to modify
273
+ * @param propertyName - Name of the property being processed
274
+ * @private
275
+ */
276
+ private applyDecorators;
277
+ /**
278
+ * Applies sensible default behaviors for properties without class-validator decorators.
279
+ * This allows the schema generator to work with plain TypeScript classes.
280
+ *
281
+ * @param property - The property information
282
+ * @param schema - The schema object to modify
283
+ * @private
284
+ */
285
+ private applySensibleDefaults;
286
+ /**
287
+ * Determines if a property should be required based on decorators and optional status.
288
+ *
289
+ * Logic:
290
+ * - If property has IsNotEmpty or ArrayNotEmpty decorator, it's required (handled in applyDecorators)
291
+ * - Otherwise, the property is not required (preserving original behavior)
292
+ * - The isOptional information is stored for future use and documentation
293
+ *
294
+ * @param property - The property information
295
+ * @param schema - The schema object to modify
296
+ * @private
297
+ */
298
+ private determineRequiredStatus;
299
+ }
300
+ /**
301
+ * Convenience function to transform a class using the singleton instance.
302
+ *
303
+ * @param cls - The class constructor function to transform
304
+ * @param options - Optional configuration for memory management
305
+ * @returns Object containing the class name and its corresponding JSON schema
306
+ *
307
+ * @example
308
+ * ```typescript
309
+ * import { transform } from 'class-validator-to-open-api'
310
+ * import { User } from './entities/user.js'
311
+ *
312
+ * const schema = transform(User)
313
+ * console.log(schema)
314
+ * ```
315
+ *
316
+ * @example
317
+ * ```typescript
318
+ * // With memory optimization
319
+ * const schema = transform(User, { maxCacheSize: 50, autoCleanup: true })
320
+ * ```
321
+ *
322
+ * @public
323
+ */
324
+ export declare function transform<T>(cls: new (...args: any[]) => T, options?: TransformerOptions): {
325
+ name: string;
326
+ schema: SchemaType;
327
+ };
328
+ export type { TransformerOptions };
329
+ export { SchemaTransformer };
@@ -0,0 +1,143 @@
1
+ declare const messages: {
2
+ errors: {
3
+ tsconfigNotFound: (path: string) => string;
4
+ classNotFound: (className: string) => string;
5
+ fileNotFound: (filePath: string) => string;
6
+ };
7
+ };
8
+ declare const constants: {
9
+ TS_CONFIG_DEFAULT_PATH: string;
10
+ jsPrimitives: {
11
+ String: {
12
+ type: string;
13
+ value: string;
14
+ };
15
+ Number: {
16
+ type: string;
17
+ value: string;
18
+ };
19
+ Boolean: {
20
+ type: string;
21
+ value: string;
22
+ };
23
+ Symbol: {
24
+ type: string;
25
+ value: string;
26
+ };
27
+ BigInt: {
28
+ type: string;
29
+ value: string;
30
+ };
31
+ null: {
32
+ type: string;
33
+ value: string;
34
+ };
35
+ Object: {
36
+ type: string;
37
+ value: string;
38
+ };
39
+ Array: {
40
+ type: string;
41
+ value: string;
42
+ };
43
+ Date: {
44
+ type: string;
45
+ value: string;
46
+ format: string;
47
+ };
48
+ Function: {
49
+ type: string;
50
+ value: string;
51
+ };
52
+ Buffer: {
53
+ type: string;
54
+ value: string;
55
+ format: string;
56
+ };
57
+ Uint8Array: {
58
+ type: string;
59
+ value: string;
60
+ format: string;
61
+ };
62
+ UploadFile: {
63
+ type: string;
64
+ value: string;
65
+ format: string;
66
+ };
67
+ File: {
68
+ type: string;
69
+ value: string;
70
+ format: string;
71
+ };
72
+ };
73
+ validatorDecorators: {
74
+ Length: {
75
+ name: string;
76
+ type: string;
77
+ };
78
+ MinLength: {
79
+ name: string;
80
+ type: string;
81
+ };
82
+ MaxLength: {
83
+ name: string;
84
+ type: string;
85
+ };
86
+ IsInt: {
87
+ name: string;
88
+ type: string;
89
+ format: string;
90
+ };
91
+ IsNumber: {
92
+ name: string;
93
+ type: string;
94
+ format: string;
95
+ };
96
+ IsString: {
97
+ name: string;
98
+ type: string;
99
+ format: string;
100
+ };
101
+ IsPositive: {
102
+ name: string;
103
+ type: string;
104
+ };
105
+ IsDate: {
106
+ name: string;
107
+ type: string;
108
+ format: string;
109
+ };
110
+ IsEmail: {
111
+ name: string;
112
+ type: string;
113
+ format: string;
114
+ };
115
+ IsNotEmpty: {
116
+ name: string;
117
+ };
118
+ IsBoolean: {
119
+ name: string;
120
+ type: string;
121
+ };
122
+ IsArray: {
123
+ name: string;
124
+ type: string;
125
+ };
126
+ Min: {
127
+ name: string;
128
+ };
129
+ Max: {
130
+ name: string;
131
+ };
132
+ ArrayNotEmpty: {
133
+ name: string;
134
+ };
135
+ ArrayMaxSize: {
136
+ name: string;
137
+ };
138
+ ArrayMinSize: {
139
+ name: string;
140
+ };
141
+ };
142
+ };
143
+ export { messages, constants };
@@ -0,0 +1,41 @@
1
+ type Property = {
2
+ [key: string]: any;
3
+ } & {
4
+ type: string;
5
+ };
6
+ type SchemaType = {
7
+ [key: string]: any;
8
+ } & {
9
+ properties: {
10
+ [key: string]: any;
11
+ };
12
+ } & {
13
+ required: string[];
14
+ } & {
15
+ type: string;
16
+ };
17
+ /**
18
+ * Information about a class-validator decorator found on a property.
19
+ * @interface DecoratorInfo
20
+ */
21
+ interface DecoratorInfo {
22
+ /** The name of the decorator (e.g., "IsString", "MinLength") */
23
+ name: string;
24
+ /** Arguments passed to the decorator */
25
+ arguments: any[];
26
+ }
27
+ /**
28
+ * Information about a class property including its type and decorators.
29
+ * @interface PropertyInfo
30
+ */
31
+ interface PropertyInfo {
32
+ /** The name of the property */
33
+ name: string;
34
+ /** The TypeScript type of the property as a string */
35
+ type: string;
36
+ /** Array of decorators applied to this property */
37
+ decorators: DecoratorInfo[];
38
+ /** Whether the property is optional (has ? operator) */
39
+ isOptional: boolean;
40
+ }
41
+ export { type SchemaType, type Property, type DecoratorInfo, type PropertyInfo };
package/package.json ADDED
@@ -0,0 +1,88 @@
1
+ {
2
+ "name": "ts-class-to-openapi",
3
+ "version": "1.0.0",
4
+ "description": "Transform TypeScript classes into OpenAPI 3.1.0 schema objects, which support class-validator decorators",
5
+ "main": "./dist/index.js",
6
+ "module": "./dist/index.esm.js",
7
+ "types": "./dist/index.d.ts",
8
+ "typings": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.esm.js",
13
+ "require": "./dist/index.js"
14
+ }
15
+ },
16
+ "files": [
17
+ "dist",
18
+ "README.md",
19
+ "LICENSE"
20
+ ],
21
+ "repository": {
22
+ "type": "git",
23
+ "url": "git+https://github.com/julioolivares/ts-class-to-openapi.git"
24
+ },
25
+ "keywords": [
26
+ "ts-class-to-openapi",
27
+ "typescript-to-openapi",
28
+ "class-validator",
29
+ "openapi",
30
+ "swagger",
31
+ "typescript",
32
+ "validation",
33
+ "schema",
34
+ "api",
35
+ "dto",
36
+ "nestjs",
37
+ "express",
38
+ "decorators",
39
+ "transform",
40
+ "json-schema",
41
+ "rest-api",
42
+ "documentation"
43
+ ],
44
+ "author": "Julio Olivares",
45
+ "homepage": "https://github.com/julioolivares/ts-class-to-openapi#readme",
46
+ "bugs": {
47
+ "url": "https://github.com/julioolivares/ts-class-to-openapi/issues"
48
+ },
49
+ "license": "MIT",
50
+ "engines": {
51
+ "node": ">=16.0.0",
52
+ "npm": ">=8.0.0"
53
+ },
54
+ "engineStrict": true,
55
+ "peerDependencies": {
56
+ "class-validator": "0.14.0"
57
+ },
58
+ "peerDependenciesMeta": {
59
+ "class-validator": {
60
+ "optional": true
61
+ }
62
+ },
63
+ "dependencies": {
64
+ "typescript": "5.0.2"
65
+ },
66
+ "devDependencies": {
67
+ "@rollup/plugin-typescript": "12.1.4",
68
+ "@types/node": "24.2.1",
69
+ "class-validator": "0.14.2",
70
+ "glob": "10.3.10",
71
+ "prettier": "3.6.2",
72
+ "rollup": "4.46.2",
73
+ "tslib": "2.8.1"
74
+ },
75
+ "package": "./package-dist.json",
76
+ "scripts": {
77
+ "test": "npm run build:test && node --test dist/test.js",
78
+ "test:watch": "npm run build:test && node --test --watch dist/**/*.test.js",
79
+ "test:coverage": "npm run build:test && node --test --experimental-test-coverage dist/**/*.test.js",
80
+ "build": "rm -rf dist && rollup -c",
81
+ "build:test": "rm -rf dist && BUILD_TARGET=test rollup -c",
82
+ "build:watch": "rm -rf dist && rollup -c -w",
83
+ "dev": "node --trace-deprecation --watch dist/run.js",
84
+ "format": "prettier --write .",
85
+ "format:check": "prettier --check .",
86
+ "prepublish": "pnpm run build"
87
+ }
88
+ }