1
- import { ClassTransformOptions } from "./ClassTransformOptions" ;
2
- import { defaultMetadataStorage } from "./storage" ;
3
- import { TypeOptions } from "./metadata/ExposeExcludeOptions" ;
1
+ import { ClassTransformOptions } from "./ClassTransformOptions" ;
2
+ import { defaultMetadataStorage } from "./storage" ;
3
+ import { TypeOptions } from "./metadata/ExposeExcludeOptions" ;
4
+ import { DiscrimnatorFunction } from "./metadata/TypeMetadata" ;
4
5
5
6
export enum TransformationType {
6
7
PLAIN_TO_CLASS ,
@@ -14,33 +15,46 @@ export class TransformOperationExecutor {
14
15
// Private Properties
15
16
// -------------------------------------------------------------------------
16
17
17
- private transformedTypesMap = new Map < Object , { level : number , object : Object } > ( ) ;
18
+ private transformedTypesMap = new Map < Object , { level : number , object : Object } > ( ) ;
18
19
19
20
// -------------------------------------------------------------------------
20
21
// Constructor
21
22
// -------------------------------------------------------------------------
22
23
23
24
constructor ( private transformationType : TransformationType ,
24
- private options : ClassTransformOptions ) {
25
+ private options : ClassTransformOptions ) {
25
26
}
26
27
27
28
// -------------------------------------------------------------------------
28
29
// Public Methods
29
30
// -------------------------------------------------------------------------
30
31
31
- transform ( source : Object | Object [ ] | any ,
32
- value : Object | Object [ ] | any ,
33
- targetType : Function ,
34
- arrayType : Function ,
35
- isMap : boolean ,
36
- level : number = 0 ) {
32
+ transform ( source : Object | Object [ ] | any ,
33
+ value : Object | Object [ ] | any ,
34
+ targetType : Function | DiscrimnatorFunction [ ] ,
35
+ arrayType : Function ,
36
+ isMap : boolean ,
37
+ level : number = 0 ) {
37
38
38
39
if ( value instanceof Array || value instanceof Set ) {
39
40
const newValue = arrayType && this . transformationType === TransformationType . PLAIN_TO_CLASS ? new ( arrayType as any ) ( ) : [ ] ;
40
41
( value as any [ ] ) . forEach ( ( subValue , index ) => {
41
42
const subSource = source ? source [ index ] : undefined ;
42
43
if ( ! this . options . enableCircularCheck || ! this . isCircular ( subValue , level ) ) {
43
- const value = this . transform ( subSource , subValue , targetType , undefined , subValue instanceof Map , level + 1 ) ;
44
+ let realTargetType ;
45
+ if ( Array . isArray ( targetType ) ) {
46
+ for ( const func of targetType ) {
47
+ const potentialType = func ( subValue ) ;
48
+ if ( potentialType ) {
49
+ realTargetType = potentialType ;
50
+ break ;
51
+ }
52
+ }
53
+ if ( typeof realTargetType !== "function" ) throw Error ( "None of the given discriminator functions did return a constructor for a type." ) ;
54
+ value = this . transform ( subSource , subValue , realTargetType , undefined , subValue instanceof Map , level + 1 ) ;
55
+ } else {
56
+ value = this . transform ( subSource , subValue , targetType , undefined , subValue instanceof Map , level + 1 ) ;
57
+ }
44
58
if ( newValue instanceof Set ) {
45
59
newValue . add ( value ) ;
46
60
} else {
@@ -55,7 +69,6 @@ export class TransformOperationExecutor {
55
69
}
56
70
} ) ;
57
71
return newValue ;
58
-
59
72
} else if ( targetType === String && ! isMap ) {
60
73
return String ( value ) ;
61
74
@@ -76,16 +89,28 @@ export class TransformOperationExecutor {
76
89
77
90
} else if ( value instanceof Object ) {
78
91
92
+ if ( Array . isArray ( targetType ) ) {
93
+ for ( const func of targetType ) {
94
+ const potentialType = func ( value ) ;
95
+ if ( potentialType ) {
96
+ targetType = potentialType ;
97
+ break ;
98
+ }
99
+ }
100
+ if ( typeof targetType !== "function" ) throw Error ( "None of the given discriminator functions did return a constructor for a type." ) ;
101
+ }
102
+
79
103
// try to guess the type
80
104
if ( ! targetType && value . constructor !== Object /* && TransformationType === TransformationType.CLASS_TO_PLAIN*/ ) targetType = value . constructor ;
81
105
if ( ! targetType && source ) targetType = source . constructor ;
82
106
107
+
83
108
if ( this . options . enableCircularCheck ) {
84
109
// add transformed type to prevent circular references
85
- this . transformedTypesMap . set ( value , { level : level , object : value } ) ;
110
+ this . transformedTypesMap . set ( value , { level : level , object : value } ) ;
86
111
}
87
112
88
- const keys = this . getKeys ( targetType , value ) ;
113
+ const keys = this . getKeys ( ( targetType as Function ) , value ) ;
89
114
let newValue : any = source ? source : { } ;
90
115
if ( ! source && ( this . transformationType === TransformationType . PLAIN_TO_CLASS || this . transformationType === TransformationType . CLASS_TO_CLASS ) ) {
91
116
if ( isMap ) {
@@ -103,14 +128,14 @@ export class TransformOperationExecutor {
103
128
let valueKey = key , newValueKey = key , propertyName = key ;
104
129
if ( ! this . options . ignoreDecorators && targetType ) {
105
130
if ( this . transformationType === TransformationType . PLAIN_TO_CLASS ) {
106
- const exposeMetadata = defaultMetadataStorage . findExposeMetadataByCustomName ( targetType , key ) ;
131
+ const exposeMetadata = defaultMetadataStorage . findExposeMetadataByCustomName ( ( targetType as Function ) , key ) ;
107
132
if ( exposeMetadata ) {
108
133
propertyName = exposeMetadata . propertyName ;
109
134
newValueKey = exposeMetadata . propertyName ;
110
135
}
111
136
112
137
} else if ( this . transformationType === TransformationType . CLASS_TO_PLAIN || this . transformationType === TransformationType . CLASS_TO_CLASS ) {
113
- const exposeMetadata = defaultMetadataStorage . findExposeMetadata ( targetType , key ) ;
138
+ const exposeMetadata = defaultMetadataStorage . findExposeMetadata ( ( targetType as Function ) , key ) ;
114
139
if ( exposeMetadata && exposeMetadata . options && exposeMetadata . options . name )
115
140
newValueKey = exposeMetadata . options . name ;
116
141
}
@@ -132,9 +157,9 @@ export class TransformOperationExecutor {
132
157
type = targetType ;
133
158
134
159
} else if ( targetType ) {
135
- const metadata = defaultMetadataStorage . findTypeMetadata ( targetType , propertyName ) ;
160
+ const metadata = defaultMetadataStorage . findTypeMetadata ( ( targetType as Function ) , propertyName ) ;
136
161
if ( metadata ) {
137
- const options : TypeOptions = { newObject : newValue , object : value , property : propertyName } ;
162
+ const options : TypeOptions = { newObject : newValue , object : value , property : propertyName } ;
138
163
type = metadata . typeFunction ( options ) ;
139
164
isSubValueMap = isSubValueMap || metadata . reflectedType === Map ;
140
165
} else if ( this . options . targetMaps ) { // try to find a type in target maps
@@ -145,7 +170,7 @@ export class TransformOperationExecutor {
145
170
}
146
171
147
172
// if value is an array try to get its custom array type
148
- const arrayType = value [ valueKey ] instanceof Array ? this . getReflectedType ( targetType , propertyName ) : undefined ;
173
+ const arrayType = value [ valueKey ] instanceof Array ? this . getReflectedType ( ( targetType as Function ) , propertyName ) : undefined ;
149
174
// const subValueKey = TransformationType === TransformationType.PLAIN_TO_CLASS && newKeyName ? newKeyName : key;
150
175
const subSource = source ? source [ valueKey ] : undefined ;
151
176
@@ -165,15 +190,15 @@ export class TransformOperationExecutor {
165
190
if ( ! this . options . enableCircularCheck || ! this . isCircular ( subValue , level ) ) {
166
191
let transformKey = this . transformationType === TransformationType . PLAIN_TO_CLASS ? newValueKey : key ;
167
192
let finalValue = this . transform ( subSource , subValue , type , arrayType , isSubValueMap , level + 1 ) ;
168
- finalValue = this . applyCustomTransformations ( finalValue , targetType , transformKey , value , this . transformationType ) ;
193
+ finalValue = this . applyCustomTransformations ( finalValue , ( targetType as Function ) , transformKey , value , this . transformationType ) ;
169
194
if ( newValue instanceof Map ) {
170
195
newValue . set ( newValueKey , finalValue ) ;
171
196
} else {
172
197
newValue [ newValueKey ] = finalValue ;
173
198
}
174
199
} else if ( this . transformationType === TransformationType . CLASS_TO_CLASS ) {
175
200
let finalValue = subValue ;
176
- finalValue = this . applyCustomTransformations ( finalValue , targetType , key , value , this . transformationType ) ;
201
+ finalValue = this . applyCustomTransformations ( finalValue , ( targetType as Function ) , key , value , this . transformationType ) ;
177
202
if ( newValue instanceof Map ) {
178
203
newValue . set ( newValueKey , finalValue ) ;
179
204
} else {
0 commit comments