ts-class-to-openapi 1.0.6 → 1.1.1
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/dist/__test__/entities/circular-reference-cases.d.ts +1 -0
- package/dist/__test__/entities/circular-reference-classes.d.ts +110 -0
- package/dist/__test__/entities/complex-circular-dependencies.d.ts +71 -0
- package/dist/__test__/entities/deep-nested-classes.d.ts +1 -0
- package/dist/__test__/entities/generic-circular-classes.d.ts +57 -0
- package/dist/__test__/test.d.ts +1 -4
- package/dist/__test__/testCases/circular-references.test.d.ts +1 -0
- package/dist/index.esm.js +111 -31
- package/dist/index.js +111 -31
- package/dist/run.js +112 -32
- package/dist/types.d.ts +2 -0
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test classes for circular reference scenarios
|
|
3
|
+
* These classes are designed to test the handling of recursive references
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Self-referencing class through direct property
|
|
7
|
+
*/
|
|
8
|
+
export declare class SelfReferenceDirectClass {
|
|
9
|
+
id: number;
|
|
10
|
+
name: string;
|
|
11
|
+
parent?: SelfReferenceDirectClass;
|
|
12
|
+
children: SelfReferenceDirectClass[];
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Metadata class for nested circular references
|
|
16
|
+
*/
|
|
17
|
+
export declare class NestedMetadata {
|
|
18
|
+
createdBy?: SelfReferenceNestedClass;
|
|
19
|
+
modifiedBy?: SelfReferenceNestedClass;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Self-referencing class through nested property
|
|
23
|
+
*/
|
|
24
|
+
export declare class SelfReferenceNestedClass {
|
|
25
|
+
id: number;
|
|
26
|
+
metadata: NestedMetadata;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Second class in indirect circular reference
|
|
30
|
+
*/
|
|
31
|
+
export declare class NodeDataClass {
|
|
32
|
+
description: string;
|
|
33
|
+
parentNode: NodeClass;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* First class in indirect circular reference
|
|
37
|
+
*/
|
|
38
|
+
export declare class NodeClass {
|
|
39
|
+
id: number;
|
|
40
|
+
name: string;
|
|
41
|
+
nodeData: NodeDataClass;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Third class in deep circular chain
|
|
45
|
+
*/
|
|
46
|
+
export declare class ClassC {
|
|
47
|
+
id: number;
|
|
48
|
+
value: number;
|
|
49
|
+
nextRef: ClassA;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Second class in deep circular chain
|
|
53
|
+
*/
|
|
54
|
+
export declare class ClassB {
|
|
55
|
+
id: number;
|
|
56
|
+
description: string;
|
|
57
|
+
nextRef: ClassC;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* First class in deep circular chain
|
|
61
|
+
*/
|
|
62
|
+
export declare class ClassA {
|
|
63
|
+
id: number;
|
|
64
|
+
name: string;
|
|
65
|
+
nextRef: ClassB;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Multiple circular paths in the same class
|
|
69
|
+
*/
|
|
70
|
+
export declare class MultiPathCircularClass {
|
|
71
|
+
id: number;
|
|
72
|
+
selfRef1?: MultiPathCircularClass;
|
|
73
|
+
selfRef2?: MultiPathCircularClass;
|
|
74
|
+
manyRefs: MultiPathCircularClass[];
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Base generic class that can create circular references
|
|
78
|
+
*/
|
|
79
|
+
export declare class GenericContainer {
|
|
80
|
+
value: any;
|
|
81
|
+
metadata: Record<string, any>;
|
|
82
|
+
related?: GenericContainer;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Concrete implementation with self-reference
|
|
86
|
+
*/
|
|
87
|
+
export declare class SelfReferencingGenericClass extends GenericContainer {
|
|
88
|
+
id: number;
|
|
89
|
+
name: string;
|
|
90
|
+
children: SelfReferencingGenericClass;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Classes for deeply nested circular references
|
|
94
|
+
*/
|
|
95
|
+
export declare class Level3 {
|
|
96
|
+
data: boolean;
|
|
97
|
+
refToRoot?: DeepNestedProperClasses;
|
|
98
|
+
}
|
|
99
|
+
export declare class Level2 {
|
|
100
|
+
data: number;
|
|
101
|
+
level3: Level3;
|
|
102
|
+
}
|
|
103
|
+
export declare class Level1 {
|
|
104
|
+
data: string;
|
|
105
|
+
level2: Level2;
|
|
106
|
+
}
|
|
107
|
+
export declare class DeepNestedProperClasses {
|
|
108
|
+
id: number;
|
|
109
|
+
level1: Level1;
|
|
110
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Complex inter-dependent classes with multiple circular references
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Core entity with relationships to other classes
|
|
6
|
+
*/
|
|
7
|
+
export declare class User {
|
|
8
|
+
id: number;
|
|
9
|
+
name: string;
|
|
10
|
+
email: string;
|
|
11
|
+
posts: Post[];
|
|
12
|
+
comments: Comment[];
|
|
13
|
+
profile: Profile;
|
|
14
|
+
primaryGroup?: Group;
|
|
15
|
+
manager?: User;
|
|
16
|
+
directReports: User[];
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Entity with back-reference to User
|
|
20
|
+
*/
|
|
21
|
+
export declare class Post {
|
|
22
|
+
id: number;
|
|
23
|
+
title: string;
|
|
24
|
+
content: string;
|
|
25
|
+
author: User;
|
|
26
|
+
comments: Comment[];
|
|
27
|
+
categories: Category[];
|
|
28
|
+
relatedPosts: Post[];
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Entity with multiple back-references creating complex circular dependencies
|
|
32
|
+
*/
|
|
33
|
+
export declare class Comment {
|
|
34
|
+
id: number;
|
|
35
|
+
content: string;
|
|
36
|
+
author: User;
|
|
37
|
+
post: Post;
|
|
38
|
+
parentComment?: Comment;
|
|
39
|
+
replies: Comment[];
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Entity with 1:1 relationship with User
|
|
43
|
+
*/
|
|
44
|
+
export declare class Profile {
|
|
45
|
+
id: number;
|
|
46
|
+
bio: string;
|
|
47
|
+
avatar: string;
|
|
48
|
+
user: User;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Entity with many-to-many relationship with User
|
|
52
|
+
*/
|
|
53
|
+
export declare class Group {
|
|
54
|
+
id: number;
|
|
55
|
+
name: string;
|
|
56
|
+
description: string;
|
|
57
|
+
members: User[];
|
|
58
|
+
admin: User;
|
|
59
|
+
parentGroup?: Group;
|
|
60
|
+
subGroups: Group[];
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Entity with many-to-many relationship with Post
|
|
64
|
+
*/
|
|
65
|
+
export declare class Category {
|
|
66
|
+
id: number;
|
|
67
|
+
name: string;
|
|
68
|
+
posts: Post[];
|
|
69
|
+
parentCategory?: Category;
|
|
70
|
+
subcategories: Category[];
|
|
71
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interfaces and classes for handling generic circular references
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Interface defining the contract for metadata properties
|
|
6
|
+
*/
|
|
7
|
+
export interface IMetadata {
|
|
8
|
+
createdAt?: Date;
|
|
9
|
+
updatedAt?: Date;
|
|
10
|
+
version?: number;
|
|
11
|
+
[key: string]: any;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Interface defining the contract for entities with circular references
|
|
15
|
+
*/
|
|
16
|
+
export interface ICircularReference<T> {
|
|
17
|
+
getReference(): T | undefined;
|
|
18
|
+
setReference(ref: T): void;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Interface for entities that can contain related items
|
|
22
|
+
*/
|
|
23
|
+
export interface IRelatable<T> {
|
|
24
|
+
related?: T;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Base class for containers that hold generic values with metadata
|
|
28
|
+
*/
|
|
29
|
+
export declare abstract class BaseContainer<T> implements IRelatable<BaseContainer<T>> {
|
|
30
|
+
abstract value: T;
|
|
31
|
+
metadata: IMetadata;
|
|
32
|
+
related?: BaseContainer<T>;
|
|
33
|
+
constructor();
|
|
34
|
+
protected abstract validateValue(value: T): boolean;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Generic container implementation with basic value validation
|
|
38
|
+
*/
|
|
39
|
+
export declare class GenericContainer<T> extends BaseContainer<T> {
|
|
40
|
+
value: T;
|
|
41
|
+
metadata: IMetadata & {
|
|
42
|
+
additionalInfo?: string;
|
|
43
|
+
};
|
|
44
|
+
constructor(value: T);
|
|
45
|
+
protected validateValue(value: T): boolean;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Self-referencing class that extends GenericContainer
|
|
49
|
+
*/
|
|
50
|
+
export declare class SelfReferencingGenericClass extends GenericContainer<SelfReferencingGenericClass> implements ICircularReference<SelfReferencingGenericClass> {
|
|
51
|
+
id: number;
|
|
52
|
+
name: string;
|
|
53
|
+
constructor(id: number, name: string);
|
|
54
|
+
getReference(): SelfReferencingGenericClass | undefined;
|
|
55
|
+
setReference(ref: SelfReferencingGenericClass): void;
|
|
56
|
+
protected validateValue(value: SelfReferencingGenericClass): boolean;
|
|
57
|
+
}
|
package/dist/__test__/test.d.ts
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/index.esm.js
CHANGED
|
@@ -14,10 +14,10 @@ const jsPrimitives = {
|
|
|
14
14
|
Object: { type: 'Object', value: 'object' },
|
|
15
15
|
Array: { type: 'Array', value: 'array' },
|
|
16
16
|
Date: { type: 'Date', value: 'string', format: 'date-time' },
|
|
17
|
-
Buffer: { type: 'Buffer'
|
|
18
|
-
Uint8Array: { type: 'Uint8Array'
|
|
17
|
+
Buffer: { type: 'Buffer'},
|
|
18
|
+
Uint8Array: { type: 'Uint8Array'},
|
|
19
19
|
UploadFile: { type: 'UploadFile', value: 'string', format: 'binary' },
|
|
20
|
-
File: { type: 'File'
|
|
20
|
+
File: { type: 'File'},
|
|
21
21
|
};
|
|
22
22
|
const validatorDecorators = {
|
|
23
23
|
Length: { name: 'Length'},
|
|
@@ -66,9 +66,42 @@ class SchemaTransformer {
|
|
|
66
66
|
this.program = ts.createProgram(fileNames, tsOptions);
|
|
67
67
|
this.checker = this.program.getTypeChecker();
|
|
68
68
|
}
|
|
69
|
-
getPropertiesByClassDeclaration(classNode) {
|
|
69
|
+
getPropertiesByClassDeclaration(classNode, visitedDeclarations = new Set()) {
|
|
70
|
+
if (visitedDeclarations.has(classNode)) {
|
|
71
|
+
return [];
|
|
72
|
+
}
|
|
73
|
+
visitedDeclarations.add(classNode);
|
|
74
|
+
// if no heritage clauses, get properties directly from class
|
|
75
|
+
if (!classNode.heritageClauses) {
|
|
76
|
+
return this.getPropertiesByClassMembers(classNode.members, classNode);
|
|
77
|
+
} // use heritage clauses to get properties from base classes
|
|
78
|
+
else {
|
|
79
|
+
const heritageClause = classNode.heritageClauses[0];
|
|
80
|
+
if (heritageClause &&
|
|
81
|
+
heritageClause.token === ts.SyntaxKind.ExtendsKeyword) {
|
|
82
|
+
const type = heritageClause.types[0];
|
|
83
|
+
let properties = [];
|
|
84
|
+
let baseProperties = [];
|
|
85
|
+
if (!type)
|
|
86
|
+
return [];
|
|
87
|
+
const symbol = this.checker.getSymbolAtLocation(type.expression);
|
|
88
|
+
if (!symbol)
|
|
89
|
+
return [];
|
|
90
|
+
const declaration = symbol.declarations?.[0];
|
|
91
|
+
if (declaration && ts.isClassDeclaration(declaration)) {
|
|
92
|
+
baseProperties = this.getPropertiesByClassDeclaration(declaration, visitedDeclarations);
|
|
93
|
+
}
|
|
94
|
+
properties = this.getPropertiesByClassMembers(classNode.members, classNode);
|
|
95
|
+
return baseProperties.concat(properties);
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
return this.getPropertiesByClassMembers(classNode.members, classNode);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
getPropertiesByClassMembers(members, parentClassNode) {
|
|
70
103
|
const properties = [];
|
|
71
|
-
for (const member of
|
|
104
|
+
for (const member of members) {
|
|
72
105
|
if (ts.isPropertyDeclaration(member) &&
|
|
73
106
|
member.name &&
|
|
74
107
|
ts.isIdentifier(member.name)) {
|
|
@@ -78,6 +111,8 @@ class SchemaTransformer {
|
|
|
78
111
|
const isOptional = !!member.questionToken;
|
|
79
112
|
const isGeneric = this.isPropertyTypeGeneric(member);
|
|
80
113
|
const isPrimitive = this.isPrimitiveType(type);
|
|
114
|
+
const isClassType = this.isClassType(member);
|
|
115
|
+
const isArray = this.isArrayProperty(member);
|
|
81
116
|
const property = {
|
|
82
117
|
name: propertyName,
|
|
83
118
|
type,
|
|
@@ -86,9 +121,25 @@ class SchemaTransformer {
|
|
|
86
121
|
isGeneric,
|
|
87
122
|
originalProperty: member,
|
|
88
123
|
isPrimitive,
|
|
89
|
-
isClassType
|
|
90
|
-
isArray
|
|
124
|
+
isClassType,
|
|
125
|
+
isArray,
|
|
126
|
+
isRef: false,
|
|
91
127
|
};
|
|
128
|
+
// Check for self-referencing properties to mark as $ref
|
|
129
|
+
if (property.isClassType) {
|
|
130
|
+
const declaration = this.getDeclarationProperty(property);
|
|
131
|
+
if (parentClassNode) {
|
|
132
|
+
if (declaration &&
|
|
133
|
+
declaration.name &&
|
|
134
|
+
this.checker.getSymbolAtLocation(declaration.name) ===
|
|
135
|
+
this.checker.getSymbolAtLocation(parentClassNode.name)) {
|
|
136
|
+
property.isRef = true;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
debugger;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
92
143
|
properties.push(property);
|
|
93
144
|
}
|
|
94
145
|
}
|
|
@@ -456,7 +507,7 @@ class SchemaTransformer {
|
|
|
456
507
|
}
|
|
457
508
|
return ts.isArrayTypeNode(propertyDeclaration.type);
|
|
458
509
|
}
|
|
459
|
-
getSchemaFromProperties({ properties, visitedClass, transformedSchema, }) {
|
|
510
|
+
getSchemaFromProperties({ properties, visitedClass, transformedSchema, classDeclaration, }) {
|
|
460
511
|
let schema = {};
|
|
461
512
|
const required = [];
|
|
462
513
|
for (const property of properties) {
|
|
@@ -464,6 +515,7 @@ class SchemaTransformer {
|
|
|
464
515
|
property,
|
|
465
516
|
visitedClass,
|
|
466
517
|
transformedSchema,
|
|
518
|
+
classDeclaration,
|
|
467
519
|
});
|
|
468
520
|
// this.applyDecorators(property, schema as SchemaType)
|
|
469
521
|
if (!property.isOptional) {
|
|
@@ -476,17 +528,35 @@ class SchemaTransformer {
|
|
|
476
528
|
required: required.length ? required : undefined,
|
|
477
529
|
};
|
|
478
530
|
}
|
|
479
|
-
getSchemaFromProperty({ property, visitedClass, transformedSchema, }) {
|
|
531
|
+
getSchemaFromProperty({ property, visitedClass, transformedSchema, classDeclaration, }) {
|
|
480
532
|
let schema = {};
|
|
481
533
|
if (property.isPrimitive) {
|
|
482
534
|
schema = this.getSchemaFromPrimitive(property);
|
|
483
535
|
}
|
|
484
536
|
else if (property.isClassType) {
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
537
|
+
const declaration = this.getDeclarationProperty(property);
|
|
538
|
+
if (property.isRef && classDeclaration.name) {
|
|
539
|
+
// Self-referencing property, handle as a reference to avoid infinite recursion
|
|
540
|
+
if (property.isArray) {
|
|
541
|
+
schema.type = 'array';
|
|
542
|
+
schema.items = {
|
|
543
|
+
$ref: `#/components/schemas/${classDeclaration.name.text}`,
|
|
544
|
+
};
|
|
545
|
+
}
|
|
546
|
+
else {
|
|
547
|
+
schema = {
|
|
548
|
+
$ref: `#/components/schemas/${classDeclaration.name.text}`,
|
|
549
|
+
};
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
else {
|
|
553
|
+
schema = this.getSchemaFromClass({
|
|
554
|
+
isArray: property.isArray,
|
|
555
|
+
visitedClass,
|
|
556
|
+
transformedSchema,
|
|
557
|
+
declaration,
|
|
558
|
+
});
|
|
559
|
+
}
|
|
490
560
|
}
|
|
491
561
|
else {
|
|
492
562
|
schema = { type: 'object', properties: {}, additionalProperties: true };
|
|
@@ -494,21 +564,26 @@ class SchemaTransformer {
|
|
|
494
564
|
this.applyDecorators(property, schema);
|
|
495
565
|
return schema;
|
|
496
566
|
}
|
|
497
|
-
getSchemaFromClass({
|
|
567
|
+
getSchemaFromClass({ transformedSchema = new Map(), visitedClass = new Set(), declaration, isArray, }) {
|
|
498
568
|
let schema = { type: 'object' };
|
|
499
|
-
const declaration = this.getDeclarationProperty(property);
|
|
500
569
|
if (!declaration ||
|
|
501
570
|
!ts.isClassDeclaration(declaration) ||
|
|
502
571
|
!declaration.name) {
|
|
503
572
|
return { type: 'object' };
|
|
504
573
|
}
|
|
505
574
|
if (visitedClass.has(declaration)) {
|
|
506
|
-
if (
|
|
507
|
-
|
|
575
|
+
if (isArray) {
|
|
576
|
+
schema.type = 'array';
|
|
577
|
+
schema.items = {
|
|
578
|
+
$ref: `#/components/schemas/${declaration.name.text}`,
|
|
579
|
+
};
|
|
508
580
|
}
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
581
|
+
else {
|
|
582
|
+
schema = {
|
|
583
|
+
$ref: `#/components/schemas/${declaration.name.text}`,
|
|
584
|
+
};
|
|
585
|
+
}
|
|
586
|
+
return schema;
|
|
512
587
|
}
|
|
513
588
|
visitedClass.add(declaration);
|
|
514
589
|
const properties = this.getPropertiesByClassDeclaration(declaration);
|
|
@@ -516,8 +591,9 @@ class SchemaTransformer {
|
|
|
516
591
|
properties,
|
|
517
592
|
visitedClass,
|
|
518
593
|
transformedSchema: transformedSchema,
|
|
594
|
+
classDeclaration: declaration,
|
|
519
595
|
});
|
|
520
|
-
if (
|
|
596
|
+
if (isArray) {
|
|
521
597
|
schema.type = 'array';
|
|
522
598
|
schema.items = {
|
|
523
599
|
type: transformerProps.type,
|
|
@@ -531,14 +607,12 @@ class SchemaTransformer {
|
|
|
531
607
|
schema.required = transformerProps.required;
|
|
532
608
|
}
|
|
533
609
|
transformedSchema.set(declaration.name.text, schema);
|
|
534
|
-
if (schema.properties && Object.keys(schema.properties).length === 0) {
|
|
535
|
-
schema = { type: 'object', properties: {}, additionalProperties: true };
|
|
536
|
-
}
|
|
537
610
|
return schema;
|
|
538
611
|
}
|
|
539
612
|
getSchemaFromPrimitive(property) {
|
|
540
613
|
const propertySchema = { type: 'object' };
|
|
541
614
|
const propertyType = property.type.toLowerCase().replace('[]', '').trim();
|
|
615
|
+
let isFile = false;
|
|
542
616
|
switch (propertyType) {
|
|
543
617
|
case constants.jsPrimitives.String.value:
|
|
544
618
|
propertySchema.type = constants.jsPrimitives.String.value;
|
|
@@ -555,12 +629,13 @@ class SchemaTransformer {
|
|
|
555
629
|
propertySchema.type = constants.jsPrimitives.Date.value;
|
|
556
630
|
propertySchema.format = constants.jsPrimitives.Date.format;
|
|
557
631
|
break;
|
|
558
|
-
case constants.jsPrimitives.Buffer.
|
|
559
|
-
case constants.jsPrimitives.Uint8Array.
|
|
560
|
-
case constants.jsPrimitives.File.
|
|
561
|
-
case constants.jsPrimitives.UploadFile.
|
|
632
|
+
case constants.jsPrimitives.Buffer.type.toLocaleLowerCase():
|
|
633
|
+
case constants.jsPrimitives.Uint8Array.type.toLocaleLowerCase():
|
|
634
|
+
case constants.jsPrimitives.File.type.toLocaleLowerCase():
|
|
635
|
+
case constants.jsPrimitives.UploadFile.type.toLocaleLowerCase():
|
|
562
636
|
propertySchema.type = constants.jsPrimitives.UploadFile.value;
|
|
563
637
|
propertySchema.format = constants.jsPrimitives.UploadFile.format;
|
|
638
|
+
isFile = true;
|
|
564
639
|
break;
|
|
565
640
|
case constants.jsPrimitives.Array.value:
|
|
566
641
|
propertySchema.type = constants.jsPrimitives.Array.value;
|
|
@@ -579,7 +654,9 @@ class SchemaTransformer {
|
|
|
579
654
|
}
|
|
580
655
|
if (property.isArray) {
|
|
581
656
|
propertySchema.type = `array`;
|
|
582
|
-
propertySchema.items = {
|
|
657
|
+
propertySchema.items = {
|
|
658
|
+
type: isFile ? constants.jsPrimitives.UploadFile.value : propertyType,
|
|
659
|
+
};
|
|
583
660
|
}
|
|
584
661
|
return propertySchema;
|
|
585
662
|
}
|
|
@@ -695,7 +772,10 @@ class SchemaTransformer {
|
|
|
695
772
|
return { name: cls.name, schema: {} };
|
|
696
773
|
}
|
|
697
774
|
const properties = this.getPropertiesByClassDeclaration(result.node);
|
|
698
|
-
schema = this.getSchemaFromProperties({
|
|
775
|
+
schema = this.getSchemaFromProperties({
|
|
776
|
+
properties,
|
|
777
|
+
classDeclaration: result.node,
|
|
778
|
+
});
|
|
699
779
|
return { name: cls.name, schema };
|
|
700
780
|
}
|
|
701
781
|
}
|