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 { TypeHelpOptions , Discriminator , TypeOptions } from "./metadata/ExposeExcludeOptions" ;
4
+ import { TypeMetadata } from "./metadata/TypeMetadata" ;
4
5
5
6
export enum TransformationType {
6
7
PLAIN_TO_CLASS ,
@@ -21,26 +22,45 @@ export class TransformOperationExecutor {
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 | TypeMetadata ,
35
+ arrayType : Function ,
36
+ isMap : boolean ,
37
+ level : number = 0 ) {
37
38
38
39
if ( Array . isArray ( value ) || 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 ) ) {
43
- const value = this . transform ( subSource , subValue , targetType , undefined , subValue instanceof Map , level + 1 ) ;
44
+ let realTargetType ;
45
+ if ( typeof targetType !== "function" && targetType && targetType . options && targetType . options . discriminator && targetType . options . discriminator . property && targetType . options . discriminator . subTypes ) {
46
+ if ( this . transformationType === TransformationType . PLAIN_TO_CLASS ) {
47
+ realTargetType = targetType . options . discriminator . subTypes . find ( ( subType ) => subType . name === subValue [ ( targetType as { options : TypeOptions } ) . options . discriminator . property ] ) ;
48
+ const options : TypeHelpOptions = { newObject : newValue , object : subValue , property : undefined } ;
49
+ const newType = targetType . typeFunction ( options ) ;
50
+ realTargetType === undefined ? realTargetType = newType : realTargetType = realTargetType . value ;
51
+ if ( ! targetType . options . keepDiscriminatorProperty ) delete subValue [ targetType . options . discriminator . property ] ;
52
+ }
53
+ if ( this . transformationType === TransformationType . CLASS_TO_CLASS ) {
54
+ realTargetType = subValue . constructor ;
55
+ }
56
+ if ( this . transformationType === TransformationType . CLASS_TO_PLAIN ) {
57
+ subValue [ targetType . options . discriminator . property ] = targetType . options . discriminator . subTypes . find ( ( subType ) => subType . value === subValue . constructor ) . name ;
58
+ }
59
+ } else {
60
+ realTargetType = targetType ;
61
+ }
62
+ const value = this . transform ( subSource , subValue , realTargetType , undefined , subValue instanceof Map , level + 1 ) ;
63
+
44
64
if ( newValue instanceof Set ) {
45
65
newValue . add ( value ) ;
46
66
} else {
@@ -55,7 +75,6 @@ export class TransformOperationExecutor {
55
75
}
56
76
} ) ;
57
77
return newValue ;
58
-
59
78
} else if ( targetType === String && ! isMap ) {
60
79
if ( value === null || value === undefined )
61
80
return value ;
@@ -91,7 +110,7 @@ export class TransformOperationExecutor {
91
110
this . recursionStack . add ( value ) ;
92
111
}
93
112
94
- const keys = this . getKeys ( targetType , value ) ;
113
+ const keys = this . getKeys ( ( targetType as Function ) , value ) ;
95
114
let newValue : any = source ? source : { } ;
96
115
if ( ! source && ( this . transformationType === TransformationType . PLAIN_TO_CLASS || this . transformationType === TransformationType . CLASS_TO_CLASS ) ) {
97
116
if ( isMap ) {
@@ -109,16 +128,17 @@ export class TransformOperationExecutor {
109
128
let valueKey = key , newValueKey = key , propertyName = key ;
110
129
if ( ! this . options . ignoreDecorators && targetType ) {
111
130
if ( this . transformationType === TransformationType . PLAIN_TO_CLASS ) {
112
- const exposeMetadata = defaultMetadataStorage . findExposeMetadataByCustomName ( targetType , key ) ;
131
+ const exposeMetadata = defaultMetadataStorage . findExposeMetadataByCustomName ( ( targetType as Function ) , key ) ;
113
132
if ( exposeMetadata ) {
114
133
propertyName = exposeMetadata . propertyName ;
115
134
newValueKey = exposeMetadata . propertyName ;
116
135
}
117
136
118
137
} else if ( this . transformationType === TransformationType . CLASS_TO_PLAIN || this . transformationType === TransformationType . CLASS_TO_CLASS ) {
119
- const exposeMetadata = defaultMetadataStorage . findExposeMetadata ( targetType , key ) ;
120
- if ( exposeMetadata && exposeMetadata . options && exposeMetadata . options . name )
138
+ const exposeMetadata = defaultMetadataStorage . findExposeMetadata ( ( targetType as Function ) , key ) ;
139
+ if ( exposeMetadata && exposeMetadata . options && exposeMetadata . options . name ) {
121
140
newValueKey = exposeMetadata . options . name ;
141
+ }
122
142
}
123
143
}
124
144
@@ -138,10 +158,30 @@ export class TransformOperationExecutor {
138
158
type = targetType ;
139
159
140
160
} else if ( targetType ) {
141
- const metadata = defaultMetadataStorage . findTypeMetadata ( targetType , propertyName ) ;
161
+
162
+ const metadata = defaultMetadataStorage . findTypeMetadata ( ( targetType as Function ) , propertyName ) ;
142
163
if ( metadata ) {
143
- const options : TypeOptions = { newObject : newValue , object : value , property : propertyName } ;
144
- type = metadata . typeFunction ( options ) ;
164
+ const options : TypeHelpOptions = { newObject : newValue , object : value , property : propertyName } ;
165
+ const newType = metadata . typeFunction ( options ) ;
166
+ if ( metadata . options && metadata . options . discriminator && metadata . options . discriminator . property && metadata . options . discriminator . subTypes ) {
167
+ if ( ! ( value [ valueKey ] instanceof Array ) ) {
168
+ if ( this . transformationType === TransformationType . PLAIN_TO_CLASS ) {
169
+ type = metadata . options . discriminator . subTypes . find ( ( subType ) => subType . name === subValue [ metadata . options . discriminator . property ] ) ;
170
+ type === undefined ? type = newType : type = type . value ;
171
+ if ( ! metadata . options . keepDiscriminatorProperty ) delete subValue [ metadata . options . discriminator . property ] ;
172
+ }
173
+ if ( this . transformationType === TransformationType . CLASS_TO_CLASS ) {
174
+ type = subValue . constructor ;
175
+ }
176
+ if ( this . transformationType === TransformationType . CLASS_TO_PLAIN ) {
177
+ subValue [ metadata . options . discriminator . property ] = metadata . options . discriminator . subTypes . find ( ( subType ) => subType . value === subValue . constructor ) . name ;
178
+ }
179
+ } else {
180
+ type = metadata ;
181
+ }
182
+ } else {
183
+ type = newType ;
184
+ }
145
185
isSubValueMap = isSubValueMap || metadata . reflectedType === Map ;
146
186
} else if ( this . options . targetMaps ) { // try to find a type in target maps
147
187
this . options . targetMaps
@@ -151,7 +191,8 @@ export class TransformOperationExecutor {
151
191
}
152
192
153
193
// if value is an array try to get its custom array type
154
- const arrayType = Array . isArray ( value [ valueKey ] ) ? this . getReflectedType ( targetType , propertyName ) : undefined ;
194
+ const arrayType = Array . isArray ( value [ valueKey ] ) ? this . getReflectedType ( ( targetType as Function ) , propertyName ) : undefined ;
195
+
155
196
// const subValueKey = TransformationType === TransformationType.PLAIN_TO_CLASS && newKeyName ? newKeyName : key;
156
197
const subSource = source ? source [ valueKey ] : undefined ;
157
198
@@ -176,14 +217,14 @@ export class TransformOperationExecutor {
176
217
// Get original value
177
218
finalValue = value [ transformKey ] ;
178
219
// Apply custom transformation
179
- finalValue = this . applyCustomTransformations ( finalValue , targetType , transformKey , value , this . transformationType ) ;
220
+ finalValue = this . applyCustomTransformations ( finalValue , ( targetType as Function ) , transformKey , value , this . transformationType ) ;
180
221
// If nothing change, it means no custom transformation was applied, so use the subValue.
181
222
finalValue = ( value [ transformKey ] === finalValue ) ? subValue : finalValue ;
182
223
// Apply the default transformation
183
224
finalValue = this . transform ( subSource , finalValue , type , arrayType , isSubValueMap , level + 1 ) ;
184
225
} else {
185
226
finalValue = this . transform ( subSource , subValue , type , arrayType , isSubValueMap , level + 1 ) ;
186
- finalValue = this . applyCustomTransformations ( finalValue , targetType , transformKey , value , this . transformationType ) ;
227
+ finalValue = this . applyCustomTransformations ( finalValue , ( targetType as Function ) , transformKey , value , this . transformationType ) ;
187
228
}
188
229
189
230
if ( newValue instanceof Map ) {
@@ -193,7 +234,7 @@ export class TransformOperationExecutor {
193
234
}
194
235
} else if ( this . transformationType === TransformationType . CLASS_TO_CLASS ) {
195
236
let finalValue = subValue ;
196
- finalValue = this . applyCustomTransformations ( finalValue , targetType , key , value , this . transformationType ) ;
237
+ finalValue = this . applyCustomTransformations ( finalValue , ( targetType as Function ) , key , value , this . transformationType ) ;
197
238
if ( newValue instanceof Map ) {
198
239
newValue . set ( newValueKey , finalValue ) ;
199
240
} else {
0 commit comments