ts-class-to-openapi 1.0.5 → 1.1.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.
Files changed (45) hide show
  1. package/README.md +368 -882
  2. package/dist/__test__/entities/additional-test-classes.d.ts +12 -0
  3. package/dist/__test__/entities/circular-reference-classes.d.ts +110 -0
  4. package/dist/__test__/entities/complex-circular-dependencies.d.ts +71 -0
  5. package/dist/__test__/entities/decorated-classes.d.ts +54 -0
  6. package/dist/__test__/entities/generic-circular-classes.d.ts +57 -0
  7. package/dist/__test__/entities/nested-classes.d.ts +70 -0
  8. package/dist/__test__/entities/pure-classes.d.ts +37 -0
  9. package/dist/__test__/entities/schema-validation-classes.d.ts +35 -0
  10. package/dist/__test__/index.d.ts +3 -9
  11. package/dist/__test__/testCases/schema-validation.test.d.ts +1 -0
  12. package/dist/index.d.ts +2 -2
  13. package/dist/index.esm.js +546 -1319
  14. package/dist/index.js +545 -1319
  15. package/dist/run.d.ts +1 -1
  16. package/dist/run.js +1131 -1343
  17. package/dist/transformer.d.ts +1 -575
  18. package/dist/transformer.fixtures.d.ts +21 -0
  19. package/dist/types.d.ts +40 -3
  20. package/package.json +16 -15
  21. package/dist/__test__/entities/address.entity.d.ts +0 -5
  22. package/dist/__test__/entities/array.entity.d.ts +0 -7
  23. package/dist/__test__/entities/broken.entity.d.ts +0 -7
  24. package/dist/__test__/entities/circular.entity.d.ts +0 -59
  25. package/dist/__test__/entities/complete.entity.d.ts +0 -16
  26. package/dist/__test__/entities/complex-generics.entity.d.ts +0 -33
  27. package/dist/__test__/entities/comprehensive-enum.entity.d.ts +0 -23
  28. package/dist/__test__/entities/enum.entity.d.ts +0 -29
  29. package/dist/__test__/entities/generic.entity.d.ts +0 -11
  30. package/dist/__test__/entities/optional-properties.entity.d.ts +0 -11
  31. package/dist/__test__/entities/plain.entity.d.ts +0 -19
  32. package/dist/__test__/entities/simple.entity.d.ts +0 -5
  33. package/dist/__test__/entities/upload.entity.d.ts +0 -8
  34. package/dist/__test__/entities/user-role-generic.entity.d.ts +0 -13
  35. package/dist/__test__/test-entities/duplicate-name.entity.d.ts +0 -5
  36. package/dist/__test__/test-entities/generic.entity.d.ts +0 -11
  37. /package/dist/__test__/{circular-reference.test.d.ts → entities/circular-reference-cases.d.ts} +0 -0
  38. /package/dist/__test__/{enum.test.d.ts → entities/deep-nested-classes.d.ts} +0 -0
  39. /package/dist/__test__/{generic-types.test.d.ts → test.d.ts} +0 -0
  40. /package/dist/__test__/{integration.test.d.ts → testCases/circular-references.test.d.ts} +0 -0
  41. /package/dist/__test__/{main.test.d.ts → testCases/debug.test.d.ts} +0 -0
  42. /package/dist/__test__/{optional-properties.test.d.ts → testCases/decorated-classes.test.d.ts} +0 -0
  43. /package/dist/__test__/{plain.test.d.ts → testCases/edge-cases.test.d.ts} +0 -0
  44. /package/dist/__test__/{ref-pattern.test.d.ts → testCases/nested-classes.test.d.ts} +0 -0
  45. /package/dist/__test__/{singleton-behavior.test.d.ts → testCases/pure-classes.test.d.ts} +0 -0
package/README.md CHANGED
@@ -1,50 +1,34 @@
1
1
  # 🔄 ts-class-to-openapi
2
2
 
3
- ✨ **Transform TypeScript classes into OpenAPI 3.1.0 schema objects**
3
+ ✨ **Transform TypeScript classes into OpenAPI 3.1.0 schemas**
4
4
 
5
- A powerful library that automatically converts your TypeScript classes into OpenAPI-compatible schemas. Works with **pure TypeScript classes** and **class-validator decorated classes**, with zero runtime dependencies.
5
+ A robust and efficient library that automatically transforms TypeScript classes into OpenAPI-compatible schemas. Compatible with **pure TypeScript classes** and **class-validator decorated classes**.
6
6
 
7
- > **🎯 Latest Features**:
8
- >
9
- > - **Pure TypeScript classes** without requiring any decorators or external dependencies!
10
- > - **Full enum support** with `@IsEnum` decorator for string, numeric, and object enums
7
+ > **What is OpenAPI?** OpenAPI (formerly Swagger) is the industry standard for describing REST APIs. This library generates OpenAPI 3.1.0 compatible schemas that can be used for API documentation, client SDK generation, and validation.
11
8
 
12
9
  ## 🚀 Key Features
13
10
 
14
- - ✅ **Pure TypeScript Support** - Transform any TypeScript class without decorators
15
- - ✅ **class-validator Compatible** - Enhanced schemas with validation decorators
16
- - ✅ **Enum Support** - Full support for TypeScript enums and object enums with @IsEnum
17
- - ✅ **CommonJS & ESM Compatible** - Works in any Node.js project
18
- - ✅ **Zero Runtime Dependencies** - No `reflect-metadata` or `emitDecoratorMetadata` required
19
- - ✅ **OpenAPI 3.1.0** - Industry-standard schema generation
20
- - ✅ **TypeScript Native** - Full type support and safety
21
- - ✅ **High Performance** - Singleton pattern with built-in caching
22
- - ✅ **Nested Objects** - Handles complex relationships automatically
23
- - ✅ **Typed Arrays** - Full support for arrays with validation
24
- - ✅ **File Uploads** - Binary file upload support
11
+ - ✅ **Direct transformation** - Convert any TypeScript class without additional configuration
12
+ - ✅ **Zero runtime dependencies** - No `reflect-metadata` or complex configurations required
13
+ - ✅ **class-validator integration** - Enrich schemas using validation decorators
14
+ - ✅ **Automatic documentation generation** - Generate Swagger documentation from existing classes
15
+ - ✅ **Native TypeScript support** - Full compatibility with enums, arrays, and nested objects
25
16
 
26
- ## 🎯 Why Use This Library?
17
+ ## 🎯 Quick Example
27
18
 
28
- Perfect for projects where you need to:
29
-
30
- - 🌐 **REST APIs**: Generate Swagger documentation from your existing TypeScript classes
31
- - 📚 **Auto Documentation**: Maintain consistency between TypeScript types and API contracts
32
- - 🧪 **API Testing**: Create mock data structures for testing
33
- - 🔧 **Microservices**: Ensure schema consistency across services
34
- - ⚡ **Legacy Projects**: Works without enabling `emitDecoratorMetadata`
35
- - 🎯 **Pure TypeScript**: Transform classes without any decorators
36
- - 🔍 **Enhanced Validation**: Add class-validator decorators for richer schemas
37
-
38
- ### 📋 About OpenAPI
39
-
40
- **OpenAPI** (formerly Swagger) is the industry standard specification for describing REST APIs in a structured, machine-readable format. This library generates **OpenAPI 3.1.0** compatible schemas from your TypeScript classes.
19
+ ```typescript
20
+ import { transform } from 'ts-class-to-openapi'
41
21
 
42
- **Benefits:**
22
+ class User {
23
+ id: number
24
+ name: string
25
+ email: string
26
+ age?: number
27
+ }
43
28
 
44
- - Automatic documentation generation
45
- - Client SDK generation
46
- - API testing automation
47
- - Consistency across your API ecosystem
29
+ const schema = transform(User)
30
+ // Returns complete OpenAPI schema ready for Swagger/API documentation
31
+ ```
48
32
 
49
33
  ## 📦 Installation
50
34
 
@@ -59,67 +43,77 @@ yarn add ts-class-to-openapi
59
43
  pnpm add ts-class-to-openapi
60
44
  ```
61
45
 
62
- ### For class-validator Enhanced Features
46
+ ### Additional Dependencies for class-validator
63
47
 
64
- If you want to use class-validator decorators for enhanced validation schemas:
48
+ To use validation decorators and generate more detailed schemas:
65
49
 
66
50
  ```bash
67
- # Using npm
68
51
  npm install ts-class-to-openapi class-validator
69
-
70
- # Using yarn
71
- yarn add ts-class-to-openapi class-validator
72
-
73
- # Using pnpm
74
- pnpm add ts-class-to-openapi class-validator
75
52
  ```
76
53
 
77
- > **Note**: `class-validator` is only required if you want to use validation decorators. Pure TypeScript classes work without it.
54
+ > **Note**: The `class-validator` dependency is optional and only required when using validation decorators.
78
55
 
79
- ## 🔧 Module Compatibility
56
+ ## 🎨 Class Transformation Examples
80
57
 
81
- This library is **100% compatible with both CommonJS and ESM**, allowing you to use it in any modern Node.js project.
58
+ ### 1. Basic TypeScript Class
82
59
 
83
- ### ESM (ES Modules) - Recommended
60
+ Fundamental method: transform any TypeScript class without decorators:
84
61
 
85
62
  ```typescript
86
- // ESM import
87
63
  import { transform } from 'ts-class-to-openapi'
88
- import { IsString, IsEmail, IsNotEmpty, IsEnum } from 'class-validator'
89
-
90
- enum UserType {
91
- ADMIN = 'admin',
92
- USER = 'user',
93
- }
94
64
 
65
+ // Basic TypeScript class - no decorators required
95
66
  class User {
96
- @IsString()
97
- @IsNotEmpty()
67
+ id: number
98
68
  name: string
99
-
100
- @IsEmail()
101
69
  email: string
102
-
103
- @IsEnum(UserType)
104
- type: UserType
70
+ age: number
71
+ active: boolean
72
+ tags: string[]
73
+ createdAt: Date
105
74
  }
106
75
 
107
- const schema = transform(User)
108
- console.log(JSON.stringify(schema, null, 2))
76
+ // Transform class to OpenAPI schema
77
+ const result = transform(User)
78
+ console.log(JSON.stringify(result, null, 2))
79
+ ```
80
+
81
+ **Generated output:**
82
+
83
+ ```json
84
+ {
85
+ "name": "User",
86
+ "schema": {
87
+ "type": "object",
88
+ "properties": {
89
+ "id": { "type": "number" },
90
+ "name": { "type": "string" },
91
+ "email": { "type": "string" },
92
+ "age": { "type": "number" },
93
+ "active": { "type": "boolean" },
94
+ "tags": {
95
+ "type": "array",
96
+ "items": { "type": "string" }
97
+ },
98
+ "createdAt": {
99
+ "type": "string",
100
+ "format": "date-time"
101
+ }
102
+ },
103
+ "required": ["id", "name", "email", "age", "active", "tags", "createdAt"]
104
+ }
105
+ }
109
106
  ```
110
107
 
111
- ### TypeScript with CommonJS
108
+ ### 2. Class with Advanced Validations
109
+
110
+ For more detailed schemas, class-validator decorators can be incorporated:
112
111
 
113
112
  ```typescript
114
- // TypeScript with CommonJS configuration
115
113
  import { transform } from 'ts-class-to-openapi'
116
- import { IsString, IsEmail, IsNotEmpty, IsEnum } from 'class-validator'
117
-
118
- enum UserType {
119
- ADMIN = 'admin',
120
- USER = 'user',
121
- }
114
+ import { IsString, IsEmail, IsNotEmpty, IsInt, Min, Max } from 'class-validator'
122
115
 
116
+ // Class with validation decorators
123
117
  class User {
124
118
  @IsString()
125
119
  @IsNotEmpty()
@@ -128,79 +122,125 @@ class User {
128
122
  @IsEmail()
129
123
  email: string
130
124
 
131
- @IsEnum(UserType)
132
- type: UserType
125
+ @IsInt()
126
+ @Min(18)
127
+ @Max(100)
128
+ age: number
133
129
  }
134
130
 
135
- const schema = transform(User)
136
- console.log(JSON.stringify(schema, null, 2))
131
+ const result = transform(User)
137
132
  ```
138
133
 
139
- ## ⚙️ Requirements
134
+ **Generated output:**
140
135
 
141
- - Node.js >= 14.0.0
142
- - TypeScript with minimal compiler options in `tsconfig.json`:
143
- ```json
144
- {
145
- "compilerOptions": {
146
- "experimentalDecorators": true
147
- }
136
+ ```json
137
+ {
138
+ "name": "User",
139
+ "schema": {
140
+ "type": "object",
141
+ "properties": {
142
+ "name": { "type": "string" },
143
+ "email": {
144
+ "type": "string",
145
+ "format": "email"
146
+ },
147
+ "age": {
148
+ "type": "integer",
149
+ "format": "int32",
150
+ "minimum": 18,
151
+ "maximum": 100
152
+ }
153
+ },
154
+ "required": ["name", "email", "age"]
148
155
  }
149
- ```
150
-
151
- > **Note**: The `experimentalDecorators` option is only required if you plan to use class-validator decorators. Pure TypeScript classes work without any special configuration.
152
-
153
- ## 🎨 Two Transformation Modes
156
+ }
157
+ ```
154
158
 
155
- ### 1. Pure TypeScript Classes
159
+ ### 3. Nested Objects and Arrays
156
160
 
157
- Transform any TypeScript class without requiring any decorators or external dependencies:
161
+ Automatic processing of complex relationships:
158
162
 
159
163
  ```typescript
160
164
  import { transform } from 'ts-class-to-openapi'
161
165
 
162
- // Pure TypeScript - no decorators needed
163
- class Product {
166
+ class Address {
167
+ street: string
168
+ city: string
169
+ zipCode: string
170
+ }
171
+
172
+ class Role {
164
173
  id: number
165
174
  name: string
166
- price: number
167
- inStock: boolean
168
- categories: string[]
169
- metadata: Record<string, any>
170
- createdAt: Date
175
+ permissions: string[]
176
+ }
177
+
178
+ class User {
179
+ id: number
180
+ name: string
181
+ email: string
182
+ address: Address // Nested object
183
+ roles: Role[] // Array of objects
184
+ phone?: string // Optional property
171
185
  }
172
186
 
173
- const schema = transform(Product)
187
+ const schema = transform(User)
174
188
  ```
175
189
 
176
- **Benefits:**
190
+ **Generated output:**
177
191
 
178
- - ✅ No external dependencies required
179
- - ✅ Works with existing TypeScript codebases
180
- - ✅ Zero configuration needed
181
- - ✅ Automatic type inference
182
- - ✅ Perfect for legacy projects
192
+ ```json
193
+ {
194
+ "name": "User",
195
+ "schema": {
196
+ "type": "object",
197
+ "properties": {
198
+ "id": { "type": "number" },
199
+ "name": { "type": "string" },
200
+ "email": { "type": "string" },
201
+ "address": {
202
+ "type": "object",
203
+ "properties": {
204
+ "street": { "type": "string" },
205
+ "city": { "type": "string" },
206
+ "zipCode": { "type": "string" }
207
+ },
208
+ "required": ["street", "city", "zipCode"]
209
+ },
210
+ "roles": {
211
+ "type": "array",
212
+ "items": {
213
+ "type": "object",
214
+ "properties": {
215
+ "id": { "type": "number" },
216
+ "name": { "type": "string" },
217
+ "permissions": {
218
+ "type": "array",
219
+ "items": { "type": "string" }
220
+ }
221
+ },
222
+ "required": ["id", "name", "permissions"]
223
+ }
224
+ },
225
+ "phone": { "type": "string" }
226
+ },
227
+ "required": ["id", "name", "email", "address", "roles"]
228
+ }
229
+ }
230
+ ```
183
231
 
184
- ### 2. Enhanced with class-validator
232
+ ### 4. Enumerations and Special Types
185
233
 
186
- Add validation decorators for richer, more detailed schemas:
234
+ Full compatibility with TypeScript enumerations:
187
235
 
188
236
  ```typescript
189
237
  import { transform } from 'ts-class-to-openapi'
190
- import {
191
- IsString,
192
- IsNumber,
193
- IsPositive,
194
- IsArray,
195
- IsNotEmpty,
196
- IsEnum,
197
- } from 'class-validator'
238
+ import { IsEnum } from 'class-validator'
198
239
 
199
- // Define enums for better API contracts
200
- enum ProductStatus {
201
- DRAFT = 'draft',
202
- PUBLISHED = 'published',
203
- ARCHIVED = 'archived',
240
+ enum UserType {
241
+ ADMIN = 'admin',
242
+ USER = 'user',
243
+ MODERATOR = 'moderator',
204
244
  }
205
245
 
206
246
  enum Priority {
@@ -209,164 +249,105 @@ enum Priority {
209
249
  HIGH = 3,
210
250
  }
211
251
 
212
- // Enhanced with validation decorators
213
- class Product {
214
- @IsNumber()
215
- @IsPositive()
216
- id: number
217
-
218
- @IsString()
219
- @IsNotEmpty()
220
- name: string
221
-
222
- @IsNumber()
223
- @IsPositive()
224
- price: number
225
-
226
- @IsEnum(ProductStatus)
227
- @IsNotEmpty()
228
- status: ProductStatus
252
+ class Task {
253
+ @IsEnum(UserType)
254
+ assignedTo: UserType
229
255
 
230
256
  @IsEnum(Priority)
231
257
  priority?: Priority
232
258
 
233
- @IsArray()
234
- categories: string[]
235
- }
236
-
237
- const schema = transform(Product)
238
- ```
239
-
240
- **Benefits:**
241
-
242
- - ✅ Rich validation constraints
243
- - ✅ Required field specification
244
- - ✅ Format validation (email, date, etc.)
245
- - ✅ String length constraints
246
- - ✅ Number range validation
247
- - ✅ Array size validation
248
- - ✅ Enum value constraints with automatic type detection
249
-
250
- ## 🚀 Quick Start
251
-
252
- ### Pure TypeScript Classes
253
-
254
- Transform any TypeScript class without requiring decorators:
255
-
256
- ```typescript
257
- import { transform } from 'ts-class-to-openapi'
258
-
259
- // Pure TypeScript class - no decorators needed!
260
- class User {
261
- id: number
262
- name: string
263
- email: string
264
- age: number
265
- isActive: boolean
266
- tags: string[]
267
- createdAt: Date
259
+ title: string
260
+ completed: boolean
261
+ dueDate: Date
268
262
  }
269
263
 
270
- // Transform the class to OpenAPI schema
271
- const result = transform(User)
272
- console.log(JSON.stringify(result, null, 2))
264
+ const schema = transform(Task)
273
265
  ```
274
266
 
275
- **Generated Output:**
267
+ **Generated output:**
276
268
 
277
269
  ```json
278
270
  {
279
- "name": "User",
271
+ "name": "Task",
280
272
  "schema": {
281
273
  "type": "object",
282
274
  "properties": {
283
- "id": {
284
- "type": "number"
285
- },
286
- "name": {
287
- "type": "string"
288
- },
289
- "email": {
290
- "type": "string"
291
- },
292
- "age": {
293
- "type": "number"
294
- },
295
- "isActive": {
296
- "type": "boolean"
275
+ "assignedTo": {
276
+ "type": "string",
277
+ "enum": ["admin", "user", "moderator"]
297
278
  },
298
- "tags": {
299
- "type": "array",
300
- "items": {
301
- "type": "string"
302
- }
279
+ "priority": {
280
+ "type": "number",
281
+ "enum": [1, 2, 3]
303
282
  },
304
- "createdAt": {
283
+ "title": { "type": "string" },
284
+ "completed": { "type": "boolean" },
285
+ "dueDate": {
305
286
  "type": "string",
306
287
  "format": "date-time"
307
288
  }
308
289
  },
309
- "required": ["id", "name", "email", "age", "isActive", "tags", "createdAt"]
290
+ "required": ["assignedTo", "title", "completed", "dueDate"]
310
291
  }
311
292
  }
312
293
  ```
313
294
 
314
- ### Enhanced with class-validator Decorators
295
+ ### 5. File Upload
315
296
 
316
- For more detailed validation schemas, add class-validator decorators:
297
+ Integrated support for binary file handling:
317
298
 
318
299
  ```typescript
319
300
  import { transform } from 'ts-class-to-openapi'
320
- import { IsString, IsEmail, IsNotEmpty, IsInt, Min, Max } from 'class-validator'
301
+ import { IsNotEmpty, IsOptional } from 'class-validator'
321
302
 
322
- // Define your class with validation decorators
323
- class User {
324
- @IsString()
303
+ // Custom file type definition
304
+ class UploadFile {}
305
+
306
+ class UserProfile {
325
307
  @IsNotEmpty()
326
- name: string
308
+ profilePicture: UploadFile
327
309
 
328
- @IsEmail()
329
- email: string
310
+ @IsOptional()
311
+ resume: UploadFile
330
312
 
331
- @IsInt()
332
- @Min(18)
333
- @Max(100)
334
- age: number
313
+ documents: UploadFile[] // Multiple files
335
314
  }
336
315
 
337
- // Transform the class to OpenAPI schema
338
- const result = transform(User)
339
- console.log(JSON.stringify(result, null, 2))
316
+ const schema = transform(UserProfile)
340
317
  ```
341
318
 
342
- **Generated Output:**
319
+ **Generated output:**
343
320
 
344
321
  ```json
345
322
  {
346
- "name": "User",
323
+ "name": "UserProfile",
347
324
  "schema": {
348
325
  "type": "object",
349
326
  "properties": {
350
- "name": {
351
- "type": "string"
327
+ "profilePicture": {
328
+ "type": "string",
329
+ "format": "binary"
352
330
  },
353
- "email": {
331
+ "resume": {
354
332
  "type": "string",
355
- "format": "email"
333
+ "format": "binary"
356
334
  },
357
- "age": {
358
- "type": "integer",
359
- "format": "int32",
360
- "minimum": 18,
361
- "maximum": 100
335
+ "documents": {
336
+ "type": "array",
337
+ "items": {
338
+ "type": "string",
339
+ "format": "binary"
340
+ }
362
341
  }
363
342
  },
364
- "required": ["name", "email", "age"]
343
+ "required": ["profilePicture", "documents"]
365
344
  }
366
345
  }
367
346
  ```
368
347
 
369
- ### Express.js + Swagger UI Example
348
+ ## 🌐 REST API Integration
349
+
350
+ ### Implementation with Express.js and Swagger UI
370
351
 
371
352
  ```typescript
372
353
  import express from 'express'
@@ -374,7 +355,7 @@ import swaggerUi from 'swagger-ui-express'
374
355
  import { transform } from 'ts-class-to-openapi'
375
356
  import { IsString, IsEmail, IsNotEmpty, IsInt, Min, Max } from 'class-validator'
376
357
 
377
- // Define your DTOs with validation decorators
358
+ // DTO definition with validation decorators
378
359
  class User {
379
360
  @IsString()
380
361
  @IsNotEmpty()
@@ -400,14 +381,14 @@ class CreateUserDto {
400
381
 
401
382
  const app = express()
402
383
 
403
- // Generate schemas from your classes
384
+ // Schema generation from classes
404
385
  const userSchema = transform(User)
405
386
  const createUserSchema = transform(CreateUserDto)
406
387
 
407
- // Create OpenAPI specification
408
- const swaggerSpec = {
388
+ // OpenAPI specification configuration
389
+ const swaggerSpecification = {
409
390
  openapi: '3.1.0',
410
- info: { title: 'My API', version: '1.0.0' },
391
+ info: { title: 'Management API', version: '1.0.0' },
411
392
  components: {
412
393
  schemas: {
413
394
  [userSchema.name]: userSchema.schema,
@@ -416,17 +397,15 @@ const swaggerSpec = {
416
397
  },
417
398
  }
418
399
 
419
- // Setup Swagger UI at /api-docs
420
- app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerSpec))
400
+ // Swagger UI configuration
401
+ app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerSpecification))
421
402
 
422
403
  app.listen(3000, () => {
423
- console.log('API docs available at http://localhost:3000/api-docs')
404
+ console.log('API documentation available at http://localhost:3000/api-docs')
424
405
  })
425
406
  ```
426
407
 
427
- #### Complete POST API Example with Schema Validation
428
-
429
- Here's a complete example of a POST endpoint that uses the generated schemas for both request validation and response structure:
408
+ ### Complete POST endpoint implementation with schema validation
430
409
 
431
410
  ```typescript
432
411
  import express from 'express'
@@ -442,7 +421,7 @@ import {
442
421
  IsOptional,
443
422
  } from 'class-validator'
444
423
 
445
- // Define your entities
424
+ // Domain entity definition
446
425
  class User {
447
426
  @IsInt()
448
427
  @Min(1)
@@ -465,7 +444,7 @@ class User {
465
444
  phone?: string
466
445
  }
467
446
 
468
- // DTO for creating a user
447
+ // DTO for user creation
469
448
  class CreateUserDto {
470
449
  @IsString()
471
450
  @IsNotEmpty()
@@ -484,29 +463,22 @@ class CreateUserDto {
484
463
  phone?: string
485
464
  }
486
465
 
487
- // Response wrapper (not transformed, defined manually in OpenAPI spec)
488
- interface ApiResponse<T> {
489
- data: T
490
- success: boolean
491
- }
492
-
493
466
  const app = express()
494
467
  app.use(express.json())
495
468
 
496
- // Generate schemas only for your entities
469
+ // Schema generation from classes
497
470
  const userSchema = transform(User)
498
471
  const createUserSchema = transform(CreateUserDto)
499
472
 
500
- // Create OpenAPI specification with POST endpoint
501
- const swaggerSpec = {
473
+ // Complete OpenAPI specification with POST endpoint
474
+ const swaggerSpecification = {
502
475
  openapi: '3.1.0',
503
476
  info: { title: 'User Management API', version: '1.0.0' },
504
477
  components: {
505
478
  schemas: {
506
479
  [userSchema.name]: userSchema.schema,
507
480
  [createUserSchema.name]: createUserSchema.schema,
508
- // ApiResponse schema defined manually
509
- UserApiResponse: {
481
+ UserResponse: {
510
482
  type: 'object',
511
483
  properties: {
512
484
  data: { $ref: `#/components/schemas/${userSchema.name}` },
@@ -524,7 +496,9 @@ const swaggerSpec = {
524
496
  required: true,
525
497
  content: {
526
498
  'application/json': {
527
- schema: { $ref: `#/components/schemas/${createUserSchema.name}` },
499
+ schema: {
500
+ $ref: `#/components/schemas/${createUserSchema.name}`,
501
+ },
528
502
  },
529
503
  },
530
504
  },
@@ -533,7 +507,7 @@ const swaggerSpec = {
533
507
  description: 'User created successfully',
534
508
  content: {
535
509
  'application/json': {
536
- schema: { $ref: '#/components/schemas/UserApiResponse' },
510
+ schema: { $ref: '#/components/schemas/UserResponse' },
537
511
  },
538
512
  },
539
513
  },
@@ -546,21 +520,19 @@ const swaggerSpec = {
546
520
  },
547
521
  }
548
522
 
549
- // Implement the POST endpoint
523
+ // POST endpoint implementation
550
524
  app.post('/users', (req, res) => {
551
525
  try {
552
- // In a real application, you would validate the request body
553
- // and save to database
554
526
  const userData = req.body as CreateUserDto
555
527
 
556
- // Mock user creation (replace with actual database logic)
528
+ // User creation simulation (replace with database logic)
557
529
  const newUser: User = {
558
530
  id: Math.floor(Math.random() * 1000) + 1,
559
531
  ...userData,
560
532
  }
561
533
 
562
- // Return response matching the schema
563
- const response: ApiResponse<User> = {
534
+ // Response that complies with the defined schema
535
+ const response = {
564
536
  data: newUser,
565
537
  success: true,
566
538
  }
@@ -575,409 +547,107 @@ app.post('/users', (req, res) => {
575
547
  }
576
548
  })
577
549
 
578
- // Setup Swagger UI
579
- app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerSpec))
550
+ // Swagger UI configuration
551
+ app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerSpecification))
580
552
 
581
553
  app.listen(3000, () => {
582
- console.log('API docs available at http://localhost:3000/api-docs')
554
+ console.log('API documentation available at http://localhost:3000/api-docs')
583
555
  })
584
556
  ```
585
557
 
586
- This example demonstrates:
558
+ ## 📖 API Reference
587
559
 
588
- - **Request Schema**: Uses `CreateUserDto` schema for POST body validation
589
- - **Response Schema**: Returns data in `{ data: User, success: boolean }` format
590
- - **OpenAPI Documentation**: Complete Swagger specification with request/response schemas
591
- - **Type Safety**: Full TypeScript support for request and response types
560
+ ### `transform(class: Function)`
592
561
 
593
- ### File Upload Example
562
+ Transforms a class constructor function into an OpenAPI schema object.
594
563
 
595
- ```typescript
596
- import { transform } from 'ts-class-to-openapi'
597
- import { IsNotEmpty, IsOptional } from 'class-validator'
564
+ **Parameters:**
598
565
 
599
- // Define custom file type
600
- class UploadFile {}
566
+ - `class: Function` - The class constructor function to transform
601
567
 
602
- // Create your upload DTO
603
- class ProfileUpload {
604
- @IsNotEmpty()
605
- profilePicture: UploadFile
568
+ **Returns:**
606
569
 
607
- @IsOptional()
608
- resume: UploadFile
570
+ ```typescript
571
+ {
572
+ name: string; // Class name
573
+ schema: {
574
+ type: "object";
575
+ properties: Record<string, any>;
576
+ required: string[];
577
+ }
609
578
  }
610
-
611
- // Generate schema
612
- const schema = transform(ProfileUpload)
613
- console.log(JSON.stringify(schema, null, 2))
614
579
  ```
615
580
 
616
- **Generated Output:**
617
-
618
- ```json
619
- {
620
- "name": "ProfileUpload",
621
- "schema": {
622
- "type": "object",
623
- "properties": {
624
- "profilePicture": {
625
- "type": "string",
626
- "format": "binary"
627
- },
628
- "resume": {
629
- "type": "string",
630
- "format": "binary"
631
- }
632
- },
633
- "required": ["profilePicture"]
634
- }
635
- }
636
- ```
637
-
638
- ### Advanced Example with Nested Objects and Arrays
639
-
640
- #### Pure TypeScript Classes
581
+ **Example:**
641
582
 
642
583
  ```typescript
643
584
  import { transform } from 'ts-class-to-openapi'
585
+ import { User } from './entities/user.js'
644
586
 
645
- class Role {
646
- id: number
647
- name: string
648
- permissions: string[]
649
- }
650
-
651
- class Address {
652
- street: string
653
- city: string
654
- country: string
655
- zipCode: string
656
- }
657
-
658
- class User {
659
- id: number
660
- name: string
661
- email: string
662
- age: number
663
- isActive: boolean
664
- tags: string[]
665
- createdAt: Date
666
- role: Role // Nested object
667
- addresses: Address[] // Array of objects
668
- files: Buffer[] // Binary files
669
- }
670
-
671
- const schema = transform(User)
672
- ```
673
-
674
- #### Enhanced with class-validator
675
-
676
- ```typescript
677
- import {
678
- IsString,
679
- IsInt,
680
- IsEmail,
681
- IsDate,
682
- IsArray,
683
- IsNotEmpty,
684
- MinLength,
685
- MaxLength,
686
- Min,
687
- Max,
688
- ArrayNotEmpty,
689
- } from 'class-validator'
690
-
691
- class Role {
692
- @IsInt()
693
- @IsNotEmpty()
694
- id: number
695
-
696
- @IsString()
697
- @MinLength(1)
698
- @MaxLength(50)
699
- name: string
700
- }
701
-
702
- class User {
703
- @IsInt()
704
- @IsNotEmpty()
705
- @Min(1)
706
- id: number
707
-
708
- @IsString()
709
- @MinLength(2)
710
- @MaxLength(100)
711
- name: string
712
-
713
- @IsEmail()
714
- email: string
715
-
716
- @IsArray()
717
- @ArrayNotEmpty()
718
- tags: string[]
719
-
720
- @IsDate()
721
- createdAt: Date
722
-
723
- @IsNotEmpty()
724
- role: Role // Nested object
725
-
726
- files: Buffer[] // Binary files
727
-
728
- @IsNotEmpty()
729
- avatar: UploadFile // Custom file upload type
730
- }
731
-
732
- const schema = transform(User)
733
- ```
734
-
735
- **Generated Output:**
736
-
737
- ```json
738
- {
739
- "name": "User",
740
- "schema": {
741
- "type": "object",
742
- "properties": {
743
- "id": {
744
- "type": "integer",
745
- "format": "int32",
746
- "minimum": 1
747
- },
748
- "name": {
749
- "type": "string",
750
- "minLength": 2,
751
- "maxLength": 100
752
- },
753
- "email": {
754
- "type": "string",
755
- "format": "email"
756
- },
757
- "tags": {
758
- "type": "array",
759
- "items": {
760
- "type": "string"
761
- },
762
- "minItems": 1
763
- },
764
- "createdAt": {
765
- "type": "string",
766
- "format": "date-time"
767
- },
768
- "role": {
769
- "type": "object",
770
- "properties": {
771
- "id": {
772
- "type": "integer",
773
- "format": "int32"
774
- },
775
- "name": {
776
- "type": "string",
777
- "minLength": 1,
778
- "maxLength": 50
779
- }
780
- },
781
- "required": ["id"]
782
- },
783
- "files": {
784
- "type": "array",
785
- "items": {
786
- "type": "string",
787
- "format": "binary"
788
- }
789
- },
790
- "avatar": {
791
- "type": "string",
792
- "format": "binary"
793
- }
794
- },
795
- "required": [
796
- "id",
797
- "name",
798
- "email",
799
- "tags",
800
- "createdAt",
801
- "role",
802
- "files",
803
- "avatar"
804
- ]
805
- }
806
- }
587
+ const result = transform(User)
588
+ console.log(result.name) // "User"
589
+ console.log(result.schema) // OpenAPI schema object
807
590
  ```
808
591
 
809
- > **Note**: Unlike other solutions, this package does **NOT** require `emitDecoratorMetadata: true` or `reflect-metadata`.
810
-
811
- ## 📊 Pure TypeScript vs Enhanced Mode Comparison
592
+ ## 🎯 Required Properties Rules
812
593
 
813
- | Feature | Pure TypeScript | Enhanced (class-validator) |
814
- | ---------------------- | ------------------------------------------- | ----------------------------------------- |
815
- | **Dependencies** | Zero | Requires `class-validator` |
816
- | **Configuration** | None | `experimentalDecorators: true` |
817
- | **Type Detection** | Automatic | Automatic + Decorators |
818
- | **Validation Rules** | Basic types only | Rich validation constraints |
819
- | **Required Fields** | Based on TypeScript optional operator (`?`) | TypeScript optional operator + decorators |
820
- | **String Constraints** | None | Min/max length, patterns |
821
- | **Number Constraints** | None | Min/max values, positive |
822
- | **Array Constraints** | None | Min/max items, non-empty |
823
- | **Email Validation** | None | Email format validation |
824
- | **Date Handling** | `date-time` format | `date-time` format |
825
- | **Use Case** | Existing codebases, rapid prototyping | APIs with validation, robust schemas |
826
-
827
- ### Example Comparison
594
+ ### TypeScript Optional Operator (`?`)
828
595
 
829
- **Pure TypeScript Class:**
596
+ The presence or absence of the TypeScript optional operator (`?`) determines whether a property is required:
830
597
 
831
598
  ```typescript
832
599
  class User {
833
- name: string // Required (no ? operator)
834
- email: string // Required (no ? operator)
835
- age: number // Required (no ? operator)
600
+ name: string // REQUIRED (no ? operator)
601
+ email: string // REQUIRED (no ? operator)
602
+ age?: number // OPTIONAL (has ? operator)
603
+ bio?: string // ❌ OPTIONAL (has ? operator)
836
604
  }
837
- // Generates: All properties required (no ? operator), basic types
838
- ```
839
-
840
- **Enhanced Class:**
841
-
842
- ```typescript
843
- class User {
844
- @IsString()
845
- @IsNotEmpty()
846
- name: string
847
-
848
- @IsEmail()
849
- email: string
850
605
 
851
- @IsInt()
852
- @Min(18)
853
- age: number
854
- }
855
- // Generates: All properties required, email format validation, age minimum 18
606
+ // Generated schema:
607
+ // "required": ["name", "email"]
856
608
  ```
857
609
 
858
- ## 🎨 Supported Decorators Reference
859
-
860
- ### Type Validation Decorators
861
-
862
- | Decorator | Generated Schema Property | Description |
863
- | --------------------- | ----------------------------------------------- | --------------------------- |
864
- | `@IsString()` | `type: "string"` | String type validation |
865
- | `@IsInt()` | `type: "integer", format: "int32"` | Integer type validation |
866
- | `@IsNumber()` | `type: "number", format: "double"` | Number type validation |
867
- | `@IsBoolean()` | `type: "boolean"` | Boolean type validation |
868
- | `@IsEmail()` | `type: "string", format: "email"` | Email format validation |
869
- | `@IsDate()` | `type: "string", format: "date-time"` | Date-time format validation |
870
- | `@IsEnum(enumObject)` | `type: "string/number/boolean", enum: [values]` | Enum constraint validation |
871
-
872
- ### Enum Validation with @IsEnum
610
+ ### Override via class-validator Decorators
873
611
 
874
- The `@IsEnum()` decorator provides powerful enum validation with automatic type detection and value extraction:
612
+ class-validator decorators can override the default behavior of the TypeScript optional operator:
875
613
 
876
614
  ```typescript
877
- import { transform } from 'ts-class-to-openapi'
878
- import { IsEnum, IsNotEmpty, IsArray } from 'class-validator'
879
-
880
- // String enum
881
- enum UserRole {
882
- ADMIN = 'admin',
883
- USER = 'user',
884
- MODERATOR = 'moderator',
885
- }
886
-
887
- // Numeric enum
888
- enum Priority {
889
- LOW = 1,
890
- MEDIUM = 2,
891
- HIGH = 3,
892
- }
893
-
894
- // Auto-incremented enum
895
- enum Size {
896
- SMALL, // 0
897
- MEDIUM, // 1
898
- LARGE, // 2
899
- }
900
-
901
- // Object enum with 'as const'
902
- const Status = {
903
- ACTIVE: 'active',
904
- INACTIVE: 'inactive',
905
- PENDING: 'pending',
906
- } as const
615
+ import { IsNotEmpty, IsOptional } from 'class-validator'
907
616
 
908
- class TaskEntity {
909
- @IsEnum(UserRole)
617
+ class User {
910
618
  @IsNotEmpty()
911
- assignedRole: UserRole // Required enum
912
-
913
- @IsEnum(Priority)
914
- priority?: Priority // Optional enum
915
-
916
- @IsEnum(Size)
917
- size?: Size // Auto-incremented enum
619
+ requiredField?: string // REQUIRED (@IsNotEmpty overrides ?)
918
620
 
919
- @IsEnum(Status)
920
- status?: keyof typeof Status // Object enum
621
+ @IsOptional()
622
+ optionalField: string // OPTIONAL (@IsOptional overrides absence of ?)
921
623
 
922
- @IsEnum(UserRole)
923
- @IsArray()
924
- allowedRoles?: UserRole[] // Array of enums
624
+ normalField: string // ✅ REQUIRED (no ? operator)
625
+ normalOptional?: string // ❌ OPTIONAL (has ? operator)
925
626
  }
926
627
 
927
- const result = transform(TaskEntity)
628
+ // Generated schema:
629
+ // "required": ["requiredField", "normalField"]
928
630
  ```
929
631
 
930
- **Generated Output:**
632
+ ## 🎨 Supported Decorators
931
633
 
932
- ```json
933
- {
934
- "name": "TaskEntity",
935
- "schema": {
936
- "type": "object",
937
- "properties": {
938
- "assignedRole": {
939
- "type": "string",
940
- "enum": ["admin", "user", "moderator"]
941
- },
942
- "priority": {
943
- "type": "number",
944
- "enum": [1, 2, 3]
945
- },
946
- "size": {
947
- "type": "number",
948
- "enum": [0, 1, 2]
949
- },
950
- "status": {
951
- "type": "string",
952
- "enum": ["active", "inactive", "pending"]
953
- },
954
- "allowedRoles": {
955
- "type": "array",
956
- "items": {
957
- "type": "string",
958
- "enum": ["admin", "user", "moderator"]
959
- }
960
- }
961
- },
962
- "required": ["assignedRole"]
963
- }
964
- }
965
- ```
966
-
967
- **Supported Enum Types:**
634
+ ### Type Validation Decorators
968
635
 
969
- - **String enums**: `enum Color { RED = 'red' }`
970
- - **Numeric enums**: `enum Status { ACTIVE = 1 }`
971
- - **Auto-incremented enums**: `enum Size { SMALL, MEDIUM }`
972
- - **Object enums**: `const Colors = { RED: 'red' } as const`
973
- - **Mixed enums**: `enum Mixed { NUM = 1, STR = 'text' }`
974
- - **Array of enums**: `roles: UserRole[]`
636
+ | Decorator | Generated Schema Property | Description |
637
+ | --------------------- | ----------------------------------------------- | -------------------------- |
638
+ | `@IsString()` | `type: "string"` | String type validation |
639
+ | `@IsInt()` | `type: "integer", format: "int32"` | Integer type validation |
640
+ | `@IsNumber()` | `type: "number", format: "double"` | Number type validation |
641
+ | `@IsBoolean()` | `type: "boolean"` | Boolean type validation |
642
+ | `@IsEmail()` | `type: "string", format: "email"` | Email format validation |
643
+ | `@IsDate()` | `type: "string", format: "date-time"` | Date format validation |
644
+ | `@IsEnum(enumObject)` | `type: "string/number/boolean", enum: [values]` | Enum constraint validation |
975
645
 
976
646
  ### String Validation Decorators
977
647
 
978
648
  | Decorator | Generated Schema Property | Description |
979
649
  | ------------------- | -------------------------------- | --------------------- |
980
- | `@IsNotEmpty()` | Adds to `required` array | Field is required |
650
+ | `@IsNotEmpty()` | Added to `required` array | Field is required |
981
651
  | `@MinLength(n)` | `minLength: n` | Minimum string length |
982
652
  | `@MaxLength(n)` | `maxLength: n` | Maximum string length |
983
653
  | `@Length(min, max)` | `minLength: min, maxLength: max` | String length range |
@@ -999,259 +669,146 @@ const result = transform(TaskEntity)
999
669
  | `@ArrayMinSize(n)` | `minItems: n` | Minimum array size |
1000
670
  | `@ArrayMaxSize(n)` | `maxItems: n` | Maximum array size |
1001
671
 
1002
- ### Special Type Mappings
1003
-
1004
- | TypeScript Type | Generated OpenAPI Schema | Description |
1005
- | --------------- | ------------------------------------- | ------------------------------ |
1006
- | `Date` | `type: "string", format: "date-time"` | ISO date-time string |
1007
- | `Buffer` | `type: "string", format: "binary"` | Binary data |
1008
- | `Uint8Array` | `type: "string", format: "binary"` | Binary array |
1009
- | `UploadFile` | `type: "string", format: "binary"` | Custom file upload type |
1010
- | `CustomClass` | Nested object schema | Recursive class transformation |
1011
- | `Type[]` | Array with typed items | Array of specific type |
1012
-
1013
- ### Automatic TypeScript Type Detection
1014
-
1015
- The library automatically detects and converts TypeScript types:
1016
-
1017
- ```typescript
1018
- class AutoDetectionExample {
1019
- // Primitives
1020
- id: number // → type: "number"
1021
- name: string // → type: "string"
1022
- isActive: boolean // → type: "boolean"
1023
-
1024
- // Special types
1025
- createdAt: Date // → type: "string", format: "date-time"
1026
- file: Buffer // → type: "string", format: "binary"
1027
-
1028
- // Arrays
1029
- tags: string[] // → type: "array", items: { type: "string" }
1030
- scores: number[] // → type: "array", items: { type: "number" }
1031
-
1032
- // Objects
1033
- metadata: object // → type: "object"
1034
- data: any // → No schema constraints
1035
-
1036
- // Nested classes (automatically transformed)
1037
- profile: UserProfile // → Nested object schema
1038
- }
1039
- ```
1040
-
1041
- ## 📁 File Upload Support
1042
-
1043
- The library provides built-in support for file uploads with automatic binary format mapping:
1044
-
1045
- ```typescript
1046
- import { transform } from 'ts-class-to-openapi'
1047
- import { IsNotEmpty, IsArray, IsOptional } from 'class-validator'
1048
-
1049
- // Define your custom file type
1050
- class UploadFile {}
1051
-
1052
- class DocumentUpload {
1053
- @IsNotEmpty()
1054
- document: UploadFile // Single file upload (required)
672
+ ## 📊 Comparison: Pure TypeScript vs Enhanced Mode
1055
673
 
1056
- @IsArray()
1057
- attachments: UploadFile[] // Multiple file uploads
674
+ | Feature | Pure TypeScript | Enhanced (class-validator) |
675
+ | ---------------------- | ------------------------------------- | ------------------------------------ |
676
+ | **Dependencies** | Zero | Requires `class-validator` |
677
+ | **Configuration** | None | `experimentalDecorators: true` |
678
+ | **Type Detection** | Automatic | Automatic + Decorators |
679
+ | **Validation Rules** | Basic types only | Rich validation constraints |
680
+ | **Required Fields** | Based on optional operator (`?`) | Optional operator + decorators |
681
+ | **String Constraints** | None | Min/max length, patterns |
682
+ | **Number Constraints** | None | Min/max values, positive |
683
+ | **Array Constraints** | None | Min/max items, non-empty |
684
+ | **Use Case** | Existing codebases, rapid prototyping | APIs with validation, robust schemas |
1058
685
 
1059
- @IsOptional()
1060
- avatar: UploadFile // Optional file upload
1061
- }
1062
-
1063
- // Transform to OpenAPI schema
1064
- const schema = transform(DocumentUpload)
1065
- console.log(JSON.stringify(schema, null, 2))
1066
- ```
686
+ ## ⚙️ Configuration
1067
687
 
1068
- **Generated Schema:**
688
+ ### Requirements
1069
689
 
1070
- ```json
1071
- {
1072
- "name": "DocumentUpload",
1073
- "schema": {
1074
- "type": "object",
1075
- "properties": {
1076
- "document": {
1077
- "type": "string",
1078
- "format": "binary"
1079
- },
1080
- "attachments": {
1081
- "type": "array",
1082
- "items": {
1083
- "type": "string",
1084
- "format": "binary"
1085
- }
1086
- },
1087
- "avatar": {
1088
- "type": "string",
1089
- "format": "binary"
1090
- }
1091
- },
1092
- "required": ["document", "attachments"]
690
+ - Node.js >= 14.0.0
691
+ - TypeScript with minimal compiler options in `tsconfig.json`:
692
+ ```json
693
+ {
694
+ "compilerOptions": {
695
+ "experimentalDecorators": true
696
+ }
1093
697
  }
1094
- }
1095
- ```
1096
-
1097
- ### Supported File Types
1098
-
1099
- The following types are automatically converted to binary format:
1100
-
1101
- - `Buffer` - Node.js Buffer objects
1102
- - `Uint8Array` - Typed arrays
1103
- - `UploadFile` - Custom file upload classes
1104
- - Any class ending with "File" suffix (e.g., `ImageFile`, `VideoFile`)
1105
-
1106
- ## 📖 API Reference
1107
-
1108
- ### `transform(cls: Function)`
698
+ ```
1109
699
 
1110
- Transforms a class constructor function into an OpenAPI schema object.
700
+ > **Note**: The `experimentalDecorators` option is only required if you plan to use class-validator decorators. Pure TypeScript classes work without special configuration.
1111
701
 
1112
- **Parameters:**
702
+ ### TypeScript Support
1113
703
 
1114
- - `cls: Function` - The class constructor function to transform
704
+ This library works with:
1115
705
 
1116
- **Returns:**
706
+ - ✅ Pure TypeScript classes (no decorators needed)
707
+ - ✅ class-validator decorated classes
708
+ - ✅ Mixed usage (some classes with decorators, some without)
709
+ - ✅ All TypeScript types: primitives, arrays, enums, nested objects
1117
710
 
1118
- ```typescript
1119
- {
1120
- name: string; // Class name
1121
- schema: {
1122
- type: "object";
1123
- properties: Record<string, any>;
1124
- required: string[];
1125
- }
1126
- }
1127
- ```
711
+ ### Module Compatibility
1128
712
 
1129
- **Example:**
713
+ This library is **fully compatible with CommonJS and ESM**:
1130
714
 
1131
715
  ```typescript
716
+ // ESM (recommended)
1132
717
  import { transform } from 'ts-class-to-openapi'
1133
- import { User } from './entities/user.js'
1134
718
 
1135
- const result = transform(User)
1136
- console.log(result.name) // "User"
1137
- console.log(result.schema) // OpenAPI schema object
719
+ // CommonJS
720
+ const { transform } = require('ts-class-to-openapi')
1138
721
  ```
1139
722
 
1140
- ## 🔍 Required Properties Rules
1141
-
1142
- Understanding how properties are marked as required is crucial for generating accurate schemas:
1143
-
1144
- ### TypeScript Optional Operator (`?`)
723
+ ## 🔧 Troubleshooting
1145
724
 
1146
- The presence or absence of the TypeScript optional operator (`?`) determines if a property is required:
725
+ ### Common Issues
1147
726
 
1148
- ```typescript
1149
- class User {
1150
- name: string // ✅ REQUIRED (no ? operator)
1151
- email: string // ✅ REQUIRED (no ? operator)
1152
- age?: number // ❌ OPTIONAL (has ? operator)
1153
- bio?: string // ❌ OPTIONAL (has ? operator)
1154
- }
727
+ **Error: "Cannot find module 'ts-class-to-openapi'"**
1155
728
 
1156
- // Generated schema:
1157
- // "required": ["name", "email"]
729
+ ```bash
730
+ npm install ts-class-to-openapi
1158
731
  ```
1159
732
 
1160
- ### class-validator Decorators Override
733
+ **Error: "Cannot find module 'class-validator'"**
1161
734
 
1162
- When using class-validator decorators, they can override the TypeScript optional behavior:
735
+ This dependency is only necessary for using validation decorators:
1163
736
 
1164
- ```typescript
1165
- import { IsNotEmpty, IsOptional } from 'class-validator'
737
+ ```bash
738
+ npm install class-validator
739
+ ```
1166
740
 
1167
- class User {
1168
- @IsNotEmpty()
1169
- requiredField?: string // ✅ REQUIRED (@IsNotEmpty overrides ?)
741
+ **Error: "Experimental decorators warning"**
1170
742
 
1171
- @IsOptional()
1172
- optionalField: string // ❌ OPTIONAL (@IsOptional overrides no ?)
743
+ Add the following configuration to the `tsconfig.json` file:
1173
744
 
1174
- normalField: string // ✅ REQUIRED (no ? operator)
1175
- normalOptional?: string // ❌ OPTIONAL (has ? operator)
745
+ ```json
746
+ {
747
+ "compilerOptions": {
748
+ "experimentalDecorators": true
749
+ }
1176
750
  }
1177
-
1178
- // Generated schema:
1179
- // "required": ["requiredField", "normalField"]
1180
751
  ```
1181
752
 
1182
- ### Array Properties
1183
-
1184
- Array properties follow the same rules, with additional decorators:
1185
-
1186
- ```typescript
1187
- import { ArrayNotEmpty } from 'class-validator'
1188
-
1189
- class User {
1190
- tags: string[] // ✅ REQUIRED (no ? operator)
1191
-
1192
- @ArrayNotEmpty()
1193
- categories?: string[] // ✅ REQUIRED (@ArrayNotEmpty overrides ?)
753
+ **Empty schema generated**
1194
754
 
1195
- optionalTags?: string[] // OPTIONAL (has ? operator)
1196
- }
755
+ - For pure TypeScript classes: Verify that the class contains properties with correctly defined types
756
+ - For classes with decorators: Confirm that the class includes class-validator decorators
757
+ - Verify that the class is correctly exported and imported
758
+ - Confirm that TypeScript compilation runs without errors
1197
759
 
1198
- // Generated schema:
1199
- // "required": ["tags", "categories"]
1200
- ```
760
+ **Works without decorators but wants validation?**
1201
761
 
1202
- ### Summary of Rules
762
+ Pure TypeScript classes work immediately, but if you want enhanced validation schemas:
1203
763
 
1204
- 1. **No `?` operator** Property is **REQUIRED**
1205
- 2. **Has `?` operator** Property is **OPTIONAL**
1206
- 3. **`@IsNotEmpty()` or `@ArrayNotEmpty()`** Forces **REQUIRED** (overrides `?`)
1207
- 4. **`@IsOptional()`** → Forces **OPTIONAL** (overrides no `?`)
764
+ 1. Install class-validator: `npm install class-validator`
765
+ 2. Add decorators to the corresponding properties
766
+ 3. Enable `experimentalDecorators: true` in the tsconfig.json file
1208
767
 
1209
768
  ## 🌟 Advanced Features
1210
769
 
1211
- - ✅ **Pure TypeScript Support** - Works with any TypeScript class, no decorators required
1212
- - ✅ **Zero Runtime Dependencies** - Uses TypeScript Compiler API instead of reflect-metadata
1213
- - ✅ **High Performance** - Singleton pattern with built-in caching for repeated transformations
1214
- - ✅ **Nested Object Support** - Automatically handles complex object relationships
1215
- - ✅ **Array Type Support** - Full support for typed arrays with validation constraints
1216
- - ✅ **Built-in Caching** - Avoids reprocessing the same classes multiple times
1217
- - ✅ **Type Safety** - Complete TypeScript support with proper type definitions
1218
- - ✅ **Framework Agnostic** - Works with any TypeScript project configuration
1219
- - ✅ **Comprehensive Coverage** - Supports all major class-validator decorators
1220
- - ✅ **Flexible Usage** - Use with or without validation decorators
770
+ - ✅ **Native pure TypeScript support** - Compatible with any TypeScript class without requiring decorators
771
+ - ✅ **Zero runtime dependencies** - Uses TypeScript Compiler API instead of reflect-metadata
772
+ - ✅ **Optimized performance** - Singleton pattern implementation with caching system for repeated transformations
773
+ - ✅ **Nested object processing** - Automatic handling of complex relationships between objects
774
+ - ✅ **Full typed array support** - Comprehensive compatibility with arrays and validation constraints
775
+ - ✅ **Integrated caching system** - Avoids reprocessing the same classes
776
+ - ✅ **Type safety** - Complete TypeScript support with precise type definitions
777
+ - ✅ **Framework agnostic** - Compatible with any TypeScript project configuration
1221
778
 
1222
779
  ## 🔄 Migration Guide
1223
780
 
1224
- ### From reflect-metadata Solutions
781
+ ### Migration from reflect-metadata Based Solutions
1225
782
 
1226
- If you're migrating from a solution that requires `reflect-metadata`:
783
+ For projects using solutions that require `reflect-metadata`:
1227
784
 
1228
- **Before (with reflect-metadata):**
785
+ **Previous implementation (with reflect-metadata):**
1229
786
 
1230
787
  ```typescript
1231
788
  import 'reflect-metadata'
1232
789
  import { getMetadataStorage } from 'class-validator'
1233
790
 
1234
- // Complex setup required
791
+ // Complex configuration required
1235
792
  const schema = transformClassToSchema(User)
1236
793
  ```
1237
794
 
1238
- **After (with ts-class-to-openapi):**
795
+ **New implementation (with ts-class-to-openapi):**
1239
796
 
1240
797
  ```typescript
1241
798
  import { transform } from 'ts-class-to-openapi'
1242
799
 
1243
- // Simple, clean API
800
+ // Simplified API
1244
801
  const schema = transform(User)
1245
802
  ```
1246
803
 
1247
- ### New: Pure TypeScript Support
804
+ ### New Functionality: Pure TypeScript Support
1248
805
 
1249
- The biggest advantage is that you can now transform **any TypeScript class** without requiring decorators:
806
+ The main advantage lies in the ability to transform **any TypeScript class** without requiring decorators:
1250
807
 
1251
- **Before (required decorators):**
808
+ **Previous limitation (mandatory decorators):**
1252
809
 
1253
810
  ```typescript
1254
- // This would NOT work with traditional solutions
811
+ // This approach would NOT work with traditional solutions
1255
812
  class LegacyUser {
1256
813
  id: number
1257
814
  name: string
@@ -1259,92 +816,21 @@ class LegacyUser {
1259
816
  }
1260
817
  ```
1261
818
 
1262
- **Now (works immediately):**
819
+ **Current implementation (immediate functionality):**
1263
820
 
1264
821
  ```typescript
1265
822
  import { transform } from 'ts-class-to-openapi'
1266
823
 
1267
- // This works out of the box!
824
+ // Ready-to-use functionality
1268
825
  class LegacyUser {
1269
826
  id: number
1270
827
  name: string
1271
828
  email: string
1272
829
  }
1273
830
 
1274
- const schema = transform(LegacyUser) // ✅ Works perfectly
831
+ const schema = transform(LegacyUser) // ✅ Successful operation
1275
832
  ```
1276
833
 
1277
- ### Migration Steps
1278
-
1279
- 1. **Remove reflect-metadata imports** from your entities
1280
- 2. **Remove `emitDecoratorMetadata: true`** from tsconfig.json (optional)
1281
- 3. **Update transformation code** to use the new API
1282
- 4. **Remove reflect-metadata dependency** from package.json
1283
- 5. **Optional**: Keep decorators for enhanced validation or remove them entirely
1284
-
1285
- ### TypeScript Configuration
1286
-
1287
- You only need minimal TypeScript configuration:
1288
-
1289
- ```json
1290
- {
1291
- "compilerOptions": {
1292
- "experimentalDecorators": true
1293
- // emitDecoratorMetadata: true ← NOT REQUIRED!
1294
- }
1295
- }
1296
- ```
1297
-
1298
- ## 🔧 Troubleshooting
1299
-
1300
- ### Common Issues
1301
-
1302
- **Error: "Cannot find module 'ts-class-to-openapi'"**
1303
-
1304
- ```bash
1305
- npm install ts-class-to-openapi
1306
- ```
1307
-
1308
- **Error: "Cannot find module 'class-validator'"**
1309
-
1310
- This is only needed if you want to use validation decorators:
1311
-
1312
- ```bash
1313
- npm install class-validator
1314
- ```
1315
-
1316
- **Error: "Experimental decorators warning"**
1317
- Add to your `tsconfig.json`:
1318
-
1319
- ```json
1320
- {
1321
- "compilerOptions": {
1322
- "experimentalDecorators": true
1323
- }
1324
- }
1325
- ```
1326
-
1327
- **Empty schema generated**
1328
-
1329
- - For pure TypeScript classes: Ensure your class has properly typed properties
1330
- - For class-validator enhanced: Ensure your class has class-validator decorators
1331
- - Check that the class is properly exported/imported
1332
- - Verify TypeScript compilation is working
1333
-
1334
- **Works without decorators but want validation?**
1335
-
1336
- Pure TypeScript classes work immediately, but if you want enhanced validation schemas:
1337
-
1338
- 1. Install class-validator: `npm install class-validator`
1339
- 2. Add decorators to your properties
1340
- 3. Enable `experimentalDecorators: true` in tsconfig.json
1341
-
1342
- **Nested objects not working**
1343
-
1344
- - Make sure nested classes are in the same project
1345
- - Ensure nested classes have their own decorators
1346
- - Check file paths and imports
1347
-
1348
834
  ## 📄 License
1349
835
 
1350
836
  MIT