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.
- package/LICENSE +21 -0
- package/README.md +959 -0
- package/dist/__test__/entities/address.entity.d.ts +5 -0
- package/dist/__test__/entities/array.entity.d.ts +7 -0
- package/dist/__test__/entities/broken.entity.d.ts +7 -0
- package/dist/__test__/entities/complete.entity.d.ts +16 -0
- package/dist/__test__/entities/generic.entity.d.ts +11 -0
- package/dist/__test__/entities/optional-properties.entity.d.ts +11 -0
- package/dist/__test__/entities/plain.entity.d.ts +19 -0
- package/dist/__test__/entities/simple.entity.d.ts +5 -0
- package/dist/__test__/entities/upload.entity.d.ts +8 -0
- package/dist/__test__/index.d.ts +4 -0
- package/dist/__test__/integration.test.d.ts +1 -0
- package/dist/__test__/main.test.d.ts +1 -0
- package/dist/__test__/optional-properties.test.d.ts +1 -0
- package/dist/__test__/plain.test.d.ts +1 -0
- package/dist/__test__/test-entities/duplicate-name.entity.d.ts +5 -0
- package/dist/__test__/test-entities/generic.entity.d.ts +11 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.esm.js +838 -0
- package/dist/index.js +840 -0
- package/dist/run.d.ts +1 -0
- package/dist/run.js +880 -0
- package/dist/transformer.d.ts +329 -0
- package/dist/transformer.fixtures.d.ts +143 -0
- package/dist/types.d.ts +41 -0
- package/package.json +88 -0
package/README.md
ADDED
|
@@ -0,0 +1,959 @@
|
|
|
1
|
+
# ๐ ts-class-to-openapi
|
|
2
|
+
|
|
3
|
+
โจ **Transform TypeScript classes into OpenAPI 3.1.0 schema objects**
|
|
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.
|
|
6
|
+
|
|
7
|
+
> **๐ฏ New Feature**: Now supports **pure TypeScript classes** without requiring any decorators or external dependencies! Perfect for transforming existing codebases instantly.
|
|
8
|
+
|
|
9
|
+
## ๐ Key Features
|
|
10
|
+
|
|
11
|
+
- โ
**Pure TypeScript Support** - Transform any TypeScript class without decorators
|
|
12
|
+
- โ
**class-validator Compatible** - Enhanced schemas with validation decorators
|
|
13
|
+
- โ
**CommonJS & ESM Compatible** - Works in any Node.js project
|
|
14
|
+
- โ
**Zero Runtime Dependencies** - No `reflect-metadata` or `emitDecoratorMetadata` required
|
|
15
|
+
- โ
**OpenAPI 3.1.0** - Industry-standard schema generation
|
|
16
|
+
- โ
**TypeScript Native** - Full type support and safety
|
|
17
|
+
- โ
**High Performance** - Singleton pattern with built-in caching
|
|
18
|
+
- โ
**Nested Objects** - Handles complex relationships automatically
|
|
19
|
+
- โ
**Typed Arrays** - Full support for arrays with validation
|
|
20
|
+
- โ
**File Uploads** - Binary file upload support
|
|
21
|
+
|
|
22
|
+
## ๐ฏ Why Use This Library?
|
|
23
|
+
|
|
24
|
+
Perfect for projects where you need to:
|
|
25
|
+
|
|
26
|
+
- ๐ **REST APIs**: Generate Swagger documentation from your existing TypeScript classes
|
|
27
|
+
- ๐ **Auto Documentation**: Maintain consistency between TypeScript types and API contracts
|
|
28
|
+
- ๐งช **API Testing**: Create mock data structures for testing
|
|
29
|
+
- ๐ง **Microservices**: Ensure schema consistency across services
|
|
30
|
+
- โก **Legacy Projects**: Works without enabling `emitDecoratorMetadata`
|
|
31
|
+
- ๐ฏ **Pure TypeScript**: Transform classes without any decorators
|
|
32
|
+
- ๐ **Enhanced Validation**: Add class-validator decorators for richer schemas
|
|
33
|
+
|
|
34
|
+
### ๐ About OpenAPI
|
|
35
|
+
|
|
36
|
+
**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.
|
|
37
|
+
|
|
38
|
+
**Benefits:**
|
|
39
|
+
|
|
40
|
+
- Automatic documentation generation
|
|
41
|
+
- Client SDK generation
|
|
42
|
+
- API testing automation
|
|
43
|
+
- Consistency across your API ecosystem
|
|
44
|
+
|
|
45
|
+
## ๐ฆ Installation
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
# Using npm
|
|
49
|
+
npm install ts-class-to-openapi
|
|
50
|
+
|
|
51
|
+
# Using yarn
|
|
52
|
+
yarn add ts-class-to-openapi
|
|
53
|
+
|
|
54
|
+
# Using pnpm
|
|
55
|
+
pnpm add ts-class-to-openapi
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### For class-validator Enhanced Features
|
|
59
|
+
|
|
60
|
+
If you want to use class-validator decorators for enhanced validation schemas:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
# Using npm
|
|
64
|
+
npm install ts-class-to-openapi class-validator
|
|
65
|
+
|
|
66
|
+
# Using yarn
|
|
67
|
+
yarn add ts-class-to-openapi class-validator
|
|
68
|
+
|
|
69
|
+
# Using pnpm
|
|
70
|
+
pnpm add ts-class-to-openapi class-validator
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
> **Note**: `class-validator` is only required if you want to use validation decorators. Pure TypeScript classes work without it.
|
|
74
|
+
|
|
75
|
+
## ๐ง Module Compatibility
|
|
76
|
+
|
|
77
|
+
This library is **100% compatible with both CommonJS and ESM**, allowing you to use it in any modern Node.js project.
|
|
78
|
+
|
|
79
|
+
### ESM (ES Modules) - Recommended
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
// ESM import
|
|
83
|
+
import { transform } from 'ts-class-to-openapi'
|
|
84
|
+
import { IsString, IsEmail, IsNotEmpty } from 'class-validator'
|
|
85
|
+
|
|
86
|
+
class User {
|
|
87
|
+
@IsString()
|
|
88
|
+
@IsNotEmpty()
|
|
89
|
+
name: string
|
|
90
|
+
|
|
91
|
+
@IsEmail()
|
|
92
|
+
email: string
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const schema = transform(User)
|
|
96
|
+
console.log(JSON.stringify(schema, null, 2))
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### TypeScript with CommonJS
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
// TypeScript with CommonJS configuration
|
|
103
|
+
import { transform } from 'ts-class-to-openapi'
|
|
104
|
+
import { IsString, IsEmail, IsNotEmpty } from 'class-validator'
|
|
105
|
+
|
|
106
|
+
class User {
|
|
107
|
+
@IsString()
|
|
108
|
+
@IsNotEmpty()
|
|
109
|
+
name: string
|
|
110
|
+
|
|
111
|
+
@IsEmail()
|
|
112
|
+
email: string
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const schema = transform(User)
|
|
116
|
+
console.log(JSON.stringify(schema, null, 2))
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## โ๏ธ Requirements
|
|
120
|
+
|
|
121
|
+
- Node.js >= 14.0.0
|
|
122
|
+
- TypeScript with minimal compiler options in `tsconfig.json`:
|
|
123
|
+
```json
|
|
124
|
+
{
|
|
125
|
+
"compilerOptions": {
|
|
126
|
+
"experimentalDecorators": true
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
> **Note**: The `experimentalDecorators` option is only required if you plan to use class-validator decorators. Pure TypeScript classes work without any special configuration.
|
|
132
|
+
|
|
133
|
+
## ๐จ Two Transformation Modes
|
|
134
|
+
|
|
135
|
+
### 1. Pure TypeScript Classes
|
|
136
|
+
|
|
137
|
+
Transform any TypeScript class without requiring any decorators or external dependencies:
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
import { transform } from 'ts-class-to-openapi'
|
|
141
|
+
|
|
142
|
+
// Pure TypeScript - no decorators needed
|
|
143
|
+
class Product {
|
|
144
|
+
id: number
|
|
145
|
+
name: string
|
|
146
|
+
price: number
|
|
147
|
+
inStock: boolean
|
|
148
|
+
categories: string[]
|
|
149
|
+
metadata: Record<string, any>
|
|
150
|
+
createdAt: Date
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const schema = transform(Product)
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
**Benefits:**
|
|
157
|
+
|
|
158
|
+
- โ
No external dependencies required
|
|
159
|
+
- โ
Works with existing TypeScript codebases
|
|
160
|
+
- โ
Zero configuration needed
|
|
161
|
+
- โ
Automatic type inference
|
|
162
|
+
- โ
Perfect for legacy projects
|
|
163
|
+
|
|
164
|
+
### 2. Enhanced with class-validator
|
|
165
|
+
|
|
166
|
+
Add validation decorators for richer, more detailed schemas:
|
|
167
|
+
|
|
168
|
+
```typescript
|
|
169
|
+
import { transform } from 'ts-class-to-openapi'
|
|
170
|
+
import {
|
|
171
|
+
IsString,
|
|
172
|
+
IsNumber,
|
|
173
|
+
IsPositive,
|
|
174
|
+
IsArray,
|
|
175
|
+
IsNotEmpty,
|
|
176
|
+
} from 'class-validator'
|
|
177
|
+
|
|
178
|
+
// Enhanced with validation decorators
|
|
179
|
+
class Product {
|
|
180
|
+
@IsNumber()
|
|
181
|
+
@IsPositive()
|
|
182
|
+
id: number
|
|
183
|
+
|
|
184
|
+
@IsString()
|
|
185
|
+
@IsNotEmpty()
|
|
186
|
+
name: string
|
|
187
|
+
|
|
188
|
+
@IsNumber()
|
|
189
|
+
@IsPositive()
|
|
190
|
+
price: number
|
|
191
|
+
|
|
192
|
+
@IsArray()
|
|
193
|
+
categories: string[]
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const schema = transform(Product)
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
**Benefits:**
|
|
200
|
+
|
|
201
|
+
- โ
Rich validation constraints
|
|
202
|
+
- โ
Required field specification
|
|
203
|
+
- โ
Format validation (email, date, etc.)
|
|
204
|
+
- โ
String length constraints
|
|
205
|
+
- โ
Number range validation
|
|
206
|
+
- โ
Array size validation
|
|
207
|
+
|
|
208
|
+
## ๐ Quick Start
|
|
209
|
+
|
|
210
|
+
### Pure TypeScript Classes
|
|
211
|
+
|
|
212
|
+
Transform any TypeScript class without requiring decorators:
|
|
213
|
+
|
|
214
|
+
```typescript
|
|
215
|
+
import { transform } from 'ts-class-to-openapi'
|
|
216
|
+
|
|
217
|
+
// Pure TypeScript class - no decorators needed!
|
|
218
|
+
class User {
|
|
219
|
+
id: number
|
|
220
|
+
name: string
|
|
221
|
+
email: string
|
|
222
|
+
age: number
|
|
223
|
+
isActive: boolean
|
|
224
|
+
tags: string[]
|
|
225
|
+
createdAt: Date
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Transform the class to OpenAPI schema
|
|
229
|
+
const result = transform(User)
|
|
230
|
+
console.log(JSON.stringify(result, null, 2))
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
**Generated Output:**
|
|
234
|
+
|
|
235
|
+
```json
|
|
236
|
+
{
|
|
237
|
+
"name": "User",
|
|
238
|
+
"schema": {
|
|
239
|
+
"type": "object",
|
|
240
|
+
"properties": {
|
|
241
|
+
"id": {
|
|
242
|
+
"type": "number"
|
|
243
|
+
},
|
|
244
|
+
"name": {
|
|
245
|
+
"type": "string"
|
|
246
|
+
},
|
|
247
|
+
"email": {
|
|
248
|
+
"type": "string"
|
|
249
|
+
},
|
|
250
|
+
"age": {
|
|
251
|
+
"type": "number"
|
|
252
|
+
},
|
|
253
|
+
"isActive": {
|
|
254
|
+
"type": "boolean"
|
|
255
|
+
},
|
|
256
|
+
"tags": {
|
|
257
|
+
"type": "array",
|
|
258
|
+
"items": {
|
|
259
|
+
"type": "string"
|
|
260
|
+
}
|
|
261
|
+
},
|
|
262
|
+
"createdAt": {
|
|
263
|
+
"type": "string",
|
|
264
|
+
"format": "date-time"
|
|
265
|
+
}
|
|
266
|
+
},
|
|
267
|
+
"required": []
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
### Enhanced with class-validator Decorators
|
|
273
|
+
|
|
274
|
+
For more detailed validation schemas, add class-validator decorators:
|
|
275
|
+
|
|
276
|
+
```typescript
|
|
277
|
+
import { transform } from 'ts-class-to-openapi'
|
|
278
|
+
import { IsString, IsEmail, IsNotEmpty, IsInt, Min, Max } from 'class-validator'
|
|
279
|
+
|
|
280
|
+
// Define your class with validation decorators
|
|
281
|
+
class User {
|
|
282
|
+
@IsString()
|
|
283
|
+
@IsNotEmpty()
|
|
284
|
+
name: string
|
|
285
|
+
|
|
286
|
+
@IsEmail()
|
|
287
|
+
email: string
|
|
288
|
+
|
|
289
|
+
@IsInt()
|
|
290
|
+
@Min(18)
|
|
291
|
+
@Max(100)
|
|
292
|
+
age: number
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// Transform the class to OpenAPI schema
|
|
296
|
+
const result = transform(User)
|
|
297
|
+
console.log(JSON.stringify(result, null, 2))
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
**Generated Output:**
|
|
301
|
+
|
|
302
|
+
```json
|
|
303
|
+
{
|
|
304
|
+
"name": "User",
|
|
305
|
+
"schema": {
|
|
306
|
+
"type": "object",
|
|
307
|
+
"properties": {
|
|
308
|
+
"name": {
|
|
309
|
+
"type": "string"
|
|
310
|
+
},
|
|
311
|
+
"email": {
|
|
312
|
+
"type": "string",
|
|
313
|
+
"format": "email"
|
|
314
|
+
},
|
|
315
|
+
"age": {
|
|
316
|
+
"type": "integer",
|
|
317
|
+
"format": "int32",
|
|
318
|
+
"minimum": 18,
|
|
319
|
+
"maximum": 100
|
|
320
|
+
}
|
|
321
|
+
},
|
|
322
|
+
"required": ["name"]
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
### Express.js + Swagger UI Example
|
|
328
|
+
|
|
329
|
+
```typescript
|
|
330
|
+
import express from 'express'
|
|
331
|
+
import swaggerUi from 'swagger-ui-express'
|
|
332
|
+
import { transform } from 'ts-class-to-openapi'
|
|
333
|
+
import { IsString, IsEmail, IsNotEmpty, IsInt, Min, Max } from 'class-validator'
|
|
334
|
+
|
|
335
|
+
// Define your DTOs with validation decorators
|
|
336
|
+
class User {
|
|
337
|
+
@IsString()
|
|
338
|
+
@IsNotEmpty()
|
|
339
|
+
name: string
|
|
340
|
+
|
|
341
|
+
@IsEmail()
|
|
342
|
+
email: string
|
|
343
|
+
|
|
344
|
+
@IsInt()
|
|
345
|
+
@Min(18)
|
|
346
|
+
@Max(100)
|
|
347
|
+
age: number
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
class CreateUserDto {
|
|
351
|
+
@IsString()
|
|
352
|
+
@IsNotEmpty()
|
|
353
|
+
name: string
|
|
354
|
+
|
|
355
|
+
@IsEmail()
|
|
356
|
+
email: string
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
const app = express()
|
|
360
|
+
|
|
361
|
+
// Generate schemas from your classes
|
|
362
|
+
const userSchema = transform(User)
|
|
363
|
+
const createUserSchema = transform(CreateUserDto)
|
|
364
|
+
|
|
365
|
+
// Create OpenAPI specification
|
|
366
|
+
const swaggerSpec = {
|
|
367
|
+
openapi: '3.1.0',
|
|
368
|
+
info: { title: 'My API', version: '1.0.0' },
|
|
369
|
+
components: {
|
|
370
|
+
schemas: {
|
|
371
|
+
[userSchema.name]: userSchema.schema,
|
|
372
|
+
[createUserSchema.name]: createUserSchema.schema,
|
|
373
|
+
},
|
|
374
|
+
},
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
// Setup Swagger UI at /api-docs
|
|
378
|
+
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerSpec))
|
|
379
|
+
|
|
380
|
+
app.listen(3000, () => {
|
|
381
|
+
console.log('API docs available at http://localhost:3000/api-docs')
|
|
382
|
+
})
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
### File Upload Example
|
|
386
|
+
|
|
387
|
+
```typescript
|
|
388
|
+
import { transform } from 'ts-class-to-openapi'
|
|
389
|
+
import { IsNotEmpty, IsOptional } from 'class-validator'
|
|
390
|
+
|
|
391
|
+
// Define custom file type
|
|
392
|
+
class UploadFile {}
|
|
393
|
+
|
|
394
|
+
// Create your upload DTO
|
|
395
|
+
class ProfileUpload {
|
|
396
|
+
@IsNotEmpty()
|
|
397
|
+
profilePicture: UploadFile
|
|
398
|
+
|
|
399
|
+
@IsOptional()
|
|
400
|
+
resume: UploadFile
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
// Generate schema
|
|
404
|
+
const schema = transform(ProfileUpload)
|
|
405
|
+
console.log(JSON.stringify(schema, null, 2))
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
**Generated Output:**
|
|
409
|
+
|
|
410
|
+
```json
|
|
411
|
+
{
|
|
412
|
+
"name": "ProfileUpload",
|
|
413
|
+
"schema": {
|
|
414
|
+
"type": "object",
|
|
415
|
+
"properties": {
|
|
416
|
+
"profilePicture": {
|
|
417
|
+
"type": "string",
|
|
418
|
+
"format": "binary"
|
|
419
|
+
},
|
|
420
|
+
"resume": {
|
|
421
|
+
"type": "string",
|
|
422
|
+
"format": "binary"
|
|
423
|
+
}
|
|
424
|
+
},
|
|
425
|
+
"required": ["profilePicture"]
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
### Advanced Example with Nested Objects and Arrays
|
|
431
|
+
|
|
432
|
+
#### Pure TypeScript Classes
|
|
433
|
+
|
|
434
|
+
```typescript
|
|
435
|
+
import { transform } from 'ts-class-to-openapi'
|
|
436
|
+
|
|
437
|
+
class Role {
|
|
438
|
+
id: number
|
|
439
|
+
name: string
|
|
440
|
+
permissions: string[]
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
class Address {
|
|
444
|
+
street: string
|
|
445
|
+
city: string
|
|
446
|
+
country: string
|
|
447
|
+
zipCode: string
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
class User {
|
|
451
|
+
id: number
|
|
452
|
+
name: string
|
|
453
|
+
email: string
|
|
454
|
+
age: number
|
|
455
|
+
isActive: boolean
|
|
456
|
+
tags: string[]
|
|
457
|
+
createdAt: Date
|
|
458
|
+
role: Role // Nested object
|
|
459
|
+
addresses: Address[] // Array of objects
|
|
460
|
+
files: Buffer[] // Binary files
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
const schema = transform(User)
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
#### Enhanced with class-validator
|
|
467
|
+
|
|
468
|
+
```typescript
|
|
469
|
+
import {
|
|
470
|
+
IsString,
|
|
471
|
+
IsInt,
|
|
472
|
+
IsEmail,
|
|
473
|
+
IsDate,
|
|
474
|
+
IsArray,
|
|
475
|
+
IsNotEmpty,
|
|
476
|
+
MinLength,
|
|
477
|
+
MaxLength,
|
|
478
|
+
Min,
|
|
479
|
+
Max,
|
|
480
|
+
ArrayNotEmpty,
|
|
481
|
+
} from 'class-validator'
|
|
482
|
+
|
|
483
|
+
class Role {
|
|
484
|
+
@IsInt()
|
|
485
|
+
@IsNotEmpty()
|
|
486
|
+
id: number
|
|
487
|
+
|
|
488
|
+
@IsString()
|
|
489
|
+
@MinLength(1)
|
|
490
|
+
@MaxLength(50)
|
|
491
|
+
name: string
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
class User {
|
|
495
|
+
@IsInt()
|
|
496
|
+
@IsNotEmpty()
|
|
497
|
+
@Min(1)
|
|
498
|
+
id: number
|
|
499
|
+
|
|
500
|
+
@IsString()
|
|
501
|
+
@MinLength(2)
|
|
502
|
+
@MaxLength(100)
|
|
503
|
+
name: string
|
|
504
|
+
|
|
505
|
+
@IsEmail()
|
|
506
|
+
email: string
|
|
507
|
+
|
|
508
|
+
@IsArray()
|
|
509
|
+
@ArrayNotEmpty()
|
|
510
|
+
tags: string[]
|
|
511
|
+
|
|
512
|
+
@IsDate()
|
|
513
|
+
createdAt: Date
|
|
514
|
+
|
|
515
|
+
@IsNotEmpty()
|
|
516
|
+
role: Role // Nested object
|
|
517
|
+
|
|
518
|
+
files: Buffer[] // Binary files
|
|
519
|
+
|
|
520
|
+
@IsNotEmpty()
|
|
521
|
+
avatar: UploadFile // Custom file upload type
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
const schema = transform(User)
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
**Generated Output:**
|
|
528
|
+
|
|
529
|
+
```json
|
|
530
|
+
{
|
|
531
|
+
"name": "User",
|
|
532
|
+
"schema": {
|
|
533
|
+
"type": "object",
|
|
534
|
+
"properties": {
|
|
535
|
+
"id": {
|
|
536
|
+
"type": "integer",
|
|
537
|
+
"format": "int32",
|
|
538
|
+
"minimum": 1
|
|
539
|
+
},
|
|
540
|
+
"name": {
|
|
541
|
+
"type": "string",
|
|
542
|
+
"minLength": 2,
|
|
543
|
+
"maxLength": 100
|
|
544
|
+
},
|
|
545
|
+
"email": {
|
|
546
|
+
"type": "string",
|
|
547
|
+
"format": "email"
|
|
548
|
+
},
|
|
549
|
+
"tags": {
|
|
550
|
+
"type": "array",
|
|
551
|
+
"items": {
|
|
552
|
+
"type": "string"
|
|
553
|
+
},
|
|
554
|
+
"minItems": 1
|
|
555
|
+
},
|
|
556
|
+
"createdAt": {
|
|
557
|
+
"type": "string",
|
|
558
|
+
"format": "date-time"
|
|
559
|
+
},
|
|
560
|
+
"role": {
|
|
561
|
+
"type": "object",
|
|
562
|
+
"properties": {
|
|
563
|
+
"id": {
|
|
564
|
+
"type": "integer",
|
|
565
|
+
"format": "int32"
|
|
566
|
+
},
|
|
567
|
+
"name": {
|
|
568
|
+
"type": "string",
|
|
569
|
+
"minLength": 1,
|
|
570
|
+
"maxLength": 50
|
|
571
|
+
}
|
|
572
|
+
},
|
|
573
|
+
"required": ["id"]
|
|
574
|
+
},
|
|
575
|
+
"files": {
|
|
576
|
+
"type": "array",
|
|
577
|
+
"items": {
|
|
578
|
+
"type": "string",
|
|
579
|
+
"format": "binary"
|
|
580
|
+
}
|
|
581
|
+
},
|
|
582
|
+
"avatar": {
|
|
583
|
+
"type": "string",
|
|
584
|
+
"format": "binary"
|
|
585
|
+
}
|
|
586
|
+
},
|
|
587
|
+
"required": ["id", "tags", "role", "avatar"]
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
```
|
|
591
|
+
|
|
592
|
+
> **Note**: Unlike other solutions, this package does **NOT** require `emitDecoratorMetadata: true` or `reflect-metadata`.
|
|
593
|
+
|
|
594
|
+
## ๐ Pure TypeScript vs Enhanced Mode Comparison
|
|
595
|
+
|
|
596
|
+
| Feature | Pure TypeScript | Enhanced (class-validator) |
|
|
597
|
+
| ---------------------- | ------------------------------------- | ------------------------------------ |
|
|
598
|
+
| **Dependencies** | Zero | Requires `class-validator` |
|
|
599
|
+
| **Configuration** | None | `experimentalDecorators: true` |
|
|
600
|
+
| **Type Detection** | Automatic | Automatic + Decorators |
|
|
601
|
+
| **Validation Rules** | Basic types only | Rich validation constraints |
|
|
602
|
+
| **Required Fields** | None (all optional) | Specified by decorators |
|
|
603
|
+
| **String Constraints** | None | Min/max length, patterns |
|
|
604
|
+
| **Number Constraints** | None | Min/max values, positive |
|
|
605
|
+
| **Array Constraints** | None | Min/max items, non-empty |
|
|
606
|
+
| **Email Validation** | None | Email format validation |
|
|
607
|
+
| **Date Handling** | `date-time` format | `date-time` format |
|
|
608
|
+
| **Use Case** | Existing codebases, rapid prototyping | APIs with validation, robust schemas |
|
|
609
|
+
|
|
610
|
+
### Example Comparison
|
|
611
|
+
|
|
612
|
+
**Pure TypeScript Class:**
|
|
613
|
+
|
|
614
|
+
```typescript
|
|
615
|
+
class User {
|
|
616
|
+
name: string
|
|
617
|
+
email: string
|
|
618
|
+
age: number
|
|
619
|
+
}
|
|
620
|
+
// Generates: All properties optional, basic types
|
|
621
|
+
```
|
|
622
|
+
|
|
623
|
+
**Enhanced Class:**
|
|
624
|
+
|
|
625
|
+
```typescript
|
|
626
|
+
class User {
|
|
627
|
+
@IsString()
|
|
628
|
+
@IsNotEmpty()
|
|
629
|
+
name: string
|
|
630
|
+
|
|
631
|
+
@IsEmail()
|
|
632
|
+
email: string
|
|
633
|
+
|
|
634
|
+
@IsInt()
|
|
635
|
+
@Min(18)
|
|
636
|
+
age: number
|
|
637
|
+
}
|
|
638
|
+
// Generates: name required, email format validation, age minimum 18
|
|
639
|
+
```
|
|
640
|
+
|
|
641
|
+
## ๐จ Supported Decorators Reference
|
|
642
|
+
|
|
643
|
+
### Type Validation Decorators
|
|
644
|
+
|
|
645
|
+
| Decorator | Generated Schema Property | Description |
|
|
646
|
+
| -------------- | ------------------------------------- | --------------------------- |
|
|
647
|
+
| `@IsString()` | `type: "string"` | String type validation |
|
|
648
|
+
| `@IsInt()` | `type: "integer", format: "int32"` | Integer type validation |
|
|
649
|
+
| `@IsNumber()` | `type: "number", format: "double"` | Number type validation |
|
|
650
|
+
| `@IsBoolean()` | `type: "boolean"` | Boolean type validation |
|
|
651
|
+
| `@IsEmail()` | `type: "string", format: "email"` | Email format validation |
|
|
652
|
+
| `@IsDate()` | `type: "string", format: "date-time"` | Date-time format validation |
|
|
653
|
+
|
|
654
|
+
### String Validation Decorators
|
|
655
|
+
|
|
656
|
+
| Decorator | Generated Schema Property | Description |
|
|
657
|
+
| ------------------- | -------------------------------- | --------------------- |
|
|
658
|
+
| `@IsNotEmpty()` | Adds to `required` array | Field is required |
|
|
659
|
+
| `@MinLength(n)` | `minLength: n` | Minimum string length |
|
|
660
|
+
| `@MaxLength(n)` | `maxLength: n` | Maximum string length |
|
|
661
|
+
| `@Length(min, max)` | `minLength: min, maxLength: max` | String length range |
|
|
662
|
+
|
|
663
|
+
### Number Validation Decorators
|
|
664
|
+
|
|
665
|
+
| Decorator | Generated Schema Property | Description |
|
|
666
|
+
| --------------- | ------------------------- | --------------------- |
|
|
667
|
+
| `@Min(n)` | `minimum: n` | Minimum numeric value |
|
|
668
|
+
| `@Max(n)` | `maximum: n` | Maximum numeric value |
|
|
669
|
+
| `@IsPositive()` | `minimum: 0` | Positive number (โฅ 0) |
|
|
670
|
+
|
|
671
|
+
### Array Validation Decorators
|
|
672
|
+
|
|
673
|
+
| Decorator | Generated Schema Property | Description |
|
|
674
|
+
| ------------------ | ------------------------- | --------------------------- |
|
|
675
|
+
| `@IsArray()` | `type: "array"` | Array type validation |
|
|
676
|
+
| `@ArrayNotEmpty()` | `minItems: 1` + required | Non-empty array requirement |
|
|
677
|
+
| `@ArrayMinSize(n)` | `minItems: n` | Minimum array size |
|
|
678
|
+
| `@ArrayMaxSize(n)` | `maxItems: n` | Maximum array size |
|
|
679
|
+
|
|
680
|
+
### Special Type Mappings
|
|
681
|
+
|
|
682
|
+
| TypeScript Type | Generated OpenAPI Schema | Description |
|
|
683
|
+
| --------------- | ------------------------------------- | ------------------------------ |
|
|
684
|
+
| `Date` | `type: "string", format: "date-time"` | ISO date-time string |
|
|
685
|
+
| `Buffer` | `type: "string", format: "binary"` | Binary data |
|
|
686
|
+
| `Uint8Array` | `type: "string", format: "binary"` | Binary array |
|
|
687
|
+
| `UploadFile` | `type: "string", format: "binary"` | Custom file upload type |
|
|
688
|
+
| `CustomClass` | Nested object schema | Recursive class transformation |
|
|
689
|
+
| `Type[]` | Array with typed items | Array of specific type |
|
|
690
|
+
|
|
691
|
+
### Automatic TypeScript Type Detection
|
|
692
|
+
|
|
693
|
+
The library automatically detects and converts TypeScript types:
|
|
694
|
+
|
|
695
|
+
```typescript
|
|
696
|
+
class AutoDetectionExample {
|
|
697
|
+
// Primitives
|
|
698
|
+
id: number // โ type: "number"
|
|
699
|
+
name: string // โ type: "string"
|
|
700
|
+
isActive: boolean // โ type: "boolean"
|
|
701
|
+
|
|
702
|
+
// Special types
|
|
703
|
+
createdAt: Date // โ type: "string", format: "date-time"
|
|
704
|
+
file: Buffer // โ type: "string", format: "binary"
|
|
705
|
+
|
|
706
|
+
// Arrays
|
|
707
|
+
tags: string[] // โ type: "array", items: { type: "string" }
|
|
708
|
+
scores: number[] // โ type: "array", items: { type: "number" }
|
|
709
|
+
|
|
710
|
+
// Objects
|
|
711
|
+
metadata: object // โ type: "object"
|
|
712
|
+
data: any // โ No schema constraints
|
|
713
|
+
|
|
714
|
+
// Nested classes (automatically transformed)
|
|
715
|
+
profile: UserProfile // โ Nested object schema
|
|
716
|
+
}
|
|
717
|
+
```
|
|
718
|
+
|
|
719
|
+
## ๐ File Upload Support
|
|
720
|
+
|
|
721
|
+
The library provides built-in support for file uploads with automatic binary format mapping:
|
|
722
|
+
|
|
723
|
+
```typescript
|
|
724
|
+
import { transform } from 'ts-class-to-openapi'
|
|
725
|
+
import { IsNotEmpty, IsArray, IsOptional } from 'class-validator'
|
|
726
|
+
|
|
727
|
+
// Define your custom file type
|
|
728
|
+
class UploadFile {}
|
|
729
|
+
|
|
730
|
+
class DocumentUpload {
|
|
731
|
+
@IsNotEmpty()
|
|
732
|
+
document: UploadFile // Single file upload (required)
|
|
733
|
+
|
|
734
|
+
@IsArray()
|
|
735
|
+
attachments: UploadFile[] // Multiple file uploads
|
|
736
|
+
|
|
737
|
+
@IsOptional()
|
|
738
|
+
avatar: UploadFile // Optional file upload
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
// Transform to OpenAPI schema
|
|
742
|
+
const schema = transform(DocumentUpload)
|
|
743
|
+
console.log(JSON.stringify(schema, null, 2))
|
|
744
|
+
```
|
|
745
|
+
|
|
746
|
+
**Generated Schema:**
|
|
747
|
+
|
|
748
|
+
```json
|
|
749
|
+
{
|
|
750
|
+
"name": "DocumentUpload",
|
|
751
|
+
"schema": {
|
|
752
|
+
"type": "object",
|
|
753
|
+
"properties": {
|
|
754
|
+
"document": {
|
|
755
|
+
"type": "string",
|
|
756
|
+
"format": "binary"
|
|
757
|
+
},
|
|
758
|
+
"attachments": {
|
|
759
|
+
"type": "array",
|
|
760
|
+
"items": {
|
|
761
|
+
"type": "string",
|
|
762
|
+
"format": "binary"
|
|
763
|
+
}
|
|
764
|
+
},
|
|
765
|
+
"avatar": {
|
|
766
|
+
"type": "string",
|
|
767
|
+
"format": "binary"
|
|
768
|
+
}
|
|
769
|
+
},
|
|
770
|
+
"required": ["document"]
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
```
|
|
774
|
+
|
|
775
|
+
### Supported File Types
|
|
776
|
+
|
|
777
|
+
The following types are automatically converted to binary format:
|
|
778
|
+
|
|
779
|
+
- `Buffer` - Node.js Buffer objects
|
|
780
|
+
- `Uint8Array` - Typed arrays
|
|
781
|
+
- `UploadFile` - Custom file upload classes
|
|
782
|
+
- Any class ending with "File" suffix (e.g., `ImageFile`, `VideoFile`)
|
|
783
|
+
|
|
784
|
+
## ๐ API Reference
|
|
785
|
+
|
|
786
|
+
### `transform(cls: Function)`
|
|
787
|
+
|
|
788
|
+
Transforms a class constructor function into an OpenAPI schema object.
|
|
789
|
+
|
|
790
|
+
**Parameters:**
|
|
791
|
+
|
|
792
|
+
- `cls: Function` - The class constructor function to transform
|
|
793
|
+
|
|
794
|
+
**Returns:**
|
|
795
|
+
|
|
796
|
+
```typescript
|
|
797
|
+
{
|
|
798
|
+
name: string; // Class name
|
|
799
|
+
schema: {
|
|
800
|
+
type: "object";
|
|
801
|
+
properties: Record<string, any>;
|
|
802
|
+
required: string[];
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
```
|
|
806
|
+
|
|
807
|
+
**Example:**
|
|
808
|
+
|
|
809
|
+
```typescript
|
|
810
|
+
import { transform } from 'ts-class-to-openapi'
|
|
811
|
+
import { User } from './entities/user.js'
|
|
812
|
+
|
|
813
|
+
const result = transform(User)
|
|
814
|
+
console.log(result.name) // "User"
|
|
815
|
+
console.log(result.schema) // OpenAPI schema object
|
|
816
|
+
```
|
|
817
|
+
|
|
818
|
+
## ๐ Advanced Features
|
|
819
|
+
|
|
820
|
+
- โ
**Pure TypeScript Support** - Works with any TypeScript class, no decorators required
|
|
821
|
+
- โ
**Zero Runtime Dependencies** - Uses TypeScript Compiler API instead of reflect-metadata
|
|
822
|
+
- โ
**High Performance** - Singleton pattern with built-in caching for repeated transformations
|
|
823
|
+
- โ
**Nested Object Support** - Automatically handles complex object relationships
|
|
824
|
+
- โ
**Array Type Support** - Full support for typed arrays with validation constraints
|
|
825
|
+
- โ
**Built-in Caching** - Avoids reprocessing the same classes multiple times
|
|
826
|
+
- โ
**Type Safety** - Complete TypeScript support with proper type definitions
|
|
827
|
+
- โ
**Framework Agnostic** - Works with any TypeScript project configuration
|
|
828
|
+
- โ
**Comprehensive Coverage** - Supports all major class-validator decorators
|
|
829
|
+
- โ
**Flexible Usage** - Use with or without validation decorators
|
|
830
|
+
|
|
831
|
+
## ๐ Migration Guide
|
|
832
|
+
|
|
833
|
+
### From reflect-metadata Solutions
|
|
834
|
+
|
|
835
|
+
If you're migrating from a solution that requires `reflect-metadata`:
|
|
836
|
+
|
|
837
|
+
**Before (with reflect-metadata):**
|
|
838
|
+
|
|
839
|
+
```typescript
|
|
840
|
+
import 'reflect-metadata'
|
|
841
|
+
import { getMetadataStorage } from 'class-validator'
|
|
842
|
+
|
|
843
|
+
// Complex setup required
|
|
844
|
+
const schema = transformClassToSchema(User)
|
|
845
|
+
```
|
|
846
|
+
|
|
847
|
+
**After (with ts-class-to-openapi):**
|
|
848
|
+
|
|
849
|
+
```typescript
|
|
850
|
+
import { transform } from 'ts-class-to-openapi'
|
|
851
|
+
|
|
852
|
+
// Simple, clean API
|
|
853
|
+
const schema = transform(User)
|
|
854
|
+
```
|
|
855
|
+
|
|
856
|
+
### New: Pure TypeScript Support
|
|
857
|
+
|
|
858
|
+
The biggest advantage is that you can now transform **any TypeScript class** without requiring decorators:
|
|
859
|
+
|
|
860
|
+
**Before (required decorators):**
|
|
861
|
+
|
|
862
|
+
```typescript
|
|
863
|
+
// This would NOT work with traditional solutions
|
|
864
|
+
class LegacyUser {
|
|
865
|
+
id: number
|
|
866
|
+
name: string
|
|
867
|
+
email: string
|
|
868
|
+
}
|
|
869
|
+
```
|
|
870
|
+
|
|
871
|
+
**Now (works immediately):**
|
|
872
|
+
|
|
873
|
+
```typescript
|
|
874
|
+
import { transform } from 'ts-class-to-openapi'
|
|
875
|
+
|
|
876
|
+
// This works out of the box!
|
|
877
|
+
class LegacyUser {
|
|
878
|
+
id: number
|
|
879
|
+
name: string
|
|
880
|
+
email: string
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
const schema = transform(LegacyUser) // โ
Works perfectly
|
|
884
|
+
```
|
|
885
|
+
|
|
886
|
+
### Migration Steps
|
|
887
|
+
|
|
888
|
+
1. **Remove reflect-metadata imports** from your entities
|
|
889
|
+
2. **Remove `emitDecoratorMetadata: true`** from tsconfig.json (optional)
|
|
890
|
+
3. **Update transformation code** to use the new API
|
|
891
|
+
4. **Remove reflect-metadata dependency** from package.json
|
|
892
|
+
5. **Optional**: Keep decorators for enhanced validation or remove them entirely
|
|
893
|
+
|
|
894
|
+
### TypeScript Configuration
|
|
895
|
+
|
|
896
|
+
You only need minimal TypeScript configuration:
|
|
897
|
+
|
|
898
|
+
```json
|
|
899
|
+
{
|
|
900
|
+
"compilerOptions": {
|
|
901
|
+
"experimentalDecorators": true
|
|
902
|
+
// emitDecoratorMetadata: true โ NOT REQUIRED!
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
```
|
|
906
|
+
|
|
907
|
+
## ๐ง Troubleshooting
|
|
908
|
+
|
|
909
|
+
### Common Issues
|
|
910
|
+
|
|
911
|
+
**Error: "Cannot find module 'ts-class-to-openapi'"**
|
|
912
|
+
|
|
913
|
+
```bash
|
|
914
|
+
npm install ts-class-to-openapi
|
|
915
|
+
```
|
|
916
|
+
|
|
917
|
+
**Error: "Cannot find module 'class-validator'"**
|
|
918
|
+
|
|
919
|
+
This is only needed if you want to use validation decorators:
|
|
920
|
+
|
|
921
|
+
```bash
|
|
922
|
+
npm install class-validator
|
|
923
|
+
```
|
|
924
|
+
|
|
925
|
+
**Error: "Experimental decorators warning"**
|
|
926
|
+
Add to your `tsconfig.json`:
|
|
927
|
+
|
|
928
|
+
```json
|
|
929
|
+
{
|
|
930
|
+
"compilerOptions": {
|
|
931
|
+
"experimentalDecorators": true
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
```
|
|
935
|
+
|
|
936
|
+
**Empty schema generated**
|
|
937
|
+
|
|
938
|
+
- For pure TypeScript classes: Ensure your class has properly typed properties
|
|
939
|
+
- For class-validator enhanced: Ensure your class has class-validator decorators
|
|
940
|
+
- Check that the class is properly exported/imported
|
|
941
|
+
- Verify TypeScript compilation is working
|
|
942
|
+
|
|
943
|
+
**Works without decorators but want validation?**
|
|
944
|
+
|
|
945
|
+
Pure TypeScript classes work immediately, but if you want enhanced validation schemas:
|
|
946
|
+
|
|
947
|
+
1. Install class-validator: `npm install class-validator`
|
|
948
|
+
2. Add decorators to your properties
|
|
949
|
+
3. Enable `experimentalDecorators: true` in tsconfig.json
|
|
950
|
+
|
|
951
|
+
**Nested objects not working**
|
|
952
|
+
|
|
953
|
+
- Make sure nested classes are in the same project
|
|
954
|
+
- Ensure nested classes have their own decorators
|
|
955
|
+
- Check file paths and imports
|
|
956
|
+
|
|
957
|
+
## ๐ License
|
|
958
|
+
|
|
959
|
+
MIT
|