1
1
import { ClassTransformOptions } from "./ClassTransformOptions" ;
2
2
import { defaultMetadataStorage } from "./storage" ;
3
- import { TypeOptions } from "./metadata/ExposeExcludeOptions" ;
4
- import { DiscrimnatorFunction } from "./metadata/TypeMetadata" ;
3
+ import { TypeHelpOptions , Discriminator , TypeOptions } from "./metadata/ExposeExcludeOptions" ;
4
+ import { TypeMetadata } from "./metadata/TypeMetadata" ;
5
5
6
6
export enum TransformationType {
7
7
PLAIN_TO_CLASS ,
@@ -31,7 +31,7 @@ export class TransformOperationExecutor {
31
31
32
32
transform ( source : Object | Object [ ] | any ,
33
33
value : Object | Object [ ] | any ,
34
- targetType : Function | DiscrimnatorFunction [ ] ,
34
+ targetType : Function | TypeMetadata ,
35
35
arrayType : Function ,
36
36
isMap : boolean ,
37
37
level : number = 0 ) {
@@ -42,19 +42,24 @@ export class TransformOperationExecutor {
42
42
const subSource = source ? source [ index ] : undefined ;
43
43
if ( ! this . options . enableCircularCheck || ! this . isCircular ( subValue , level ) ) {
44
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
- }
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 ;
52
58
}
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
59
} else {
56
- value = this . transform ( subSource , subValue , targetType , undefined , subValue instanceof Map , level + 1 ) ;
60
+ realTargetType = targetType ;
57
61
}
62
+ const value = this . transform ( subSource , subValue , realTargetType , undefined , subValue instanceof Map , level + 1 ) ;
58
63
if ( newValue instanceof Set ) {
59
64
newValue . add ( value ) ;
60
65
} else {
@@ -89,22 +94,10 @@ export class TransformOperationExecutor {
89
94
90
95
} else if ( value instanceof Object ) {
91
96
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
-
103
97
// try to guess the type
104
98
if ( ! targetType && value . constructor !== Object /* && TransformationType === TransformationType.CLASS_TO_PLAIN*/ ) targetType = value . constructor ;
105
99
if ( ! targetType && source ) targetType = source . constructor ;
106
100
107
-
108
101
if ( this . options . enableCircularCheck ) {
109
102
// add transformed type to prevent circular references
110
103
this . transformedTypesMap . set ( value , { level : level , object : value } ) ;
@@ -136,8 +129,9 @@ export class TransformOperationExecutor {
136
129
137
130
} else if ( this . transformationType === TransformationType . CLASS_TO_PLAIN || this . transformationType === TransformationType . CLASS_TO_CLASS ) {
138
131
const exposeMetadata = defaultMetadataStorage . findExposeMetadata ( ( targetType as Function ) , key ) ;
139
- if ( exposeMetadata && exposeMetadata . options && exposeMetadata . options . name )
132
+ if ( exposeMetadata && exposeMetadata . options && exposeMetadata . options . name ) {
140
133
newValueKey = exposeMetadata . options . name ;
134
+ }
141
135
}
142
136
}
143
137
@@ -157,10 +151,30 @@ export class TransformOperationExecutor {
157
151
type = targetType ;
158
152
159
153
} else if ( targetType ) {
154
+
160
155
const metadata = defaultMetadataStorage . findTypeMetadata ( ( targetType as Function ) , propertyName ) ;
161
156
if ( metadata ) {
162
- const options : TypeOptions = { newObject : newValue , object : value , property : propertyName } ;
163
- type = metadata . typeFunction ( options ) ;
157
+ const options : TypeHelpOptions = { newObject : newValue , object : value , property : propertyName } ;
158
+ const newType = metadata . typeFunction ( options ) ;
159
+ if ( metadata . options && metadata . options . discriminator && metadata . options . discriminator . property && metadata . options . discriminator . subTypes ) {
160
+ if ( ! ( value [ valueKey ] instanceof Array ) ) {
161
+ if ( this . transformationType === TransformationType . PLAIN_TO_CLASS ) {
162
+ type = metadata . options . discriminator . subTypes . find ( ( subType ) => subType . name === subValue [ metadata . options . discriminator . property ] ) ;
163
+ type === undefined ? type = newType : type = type . value ;
164
+ if ( ! metadata . options . keepDiscriminatorProperty ) delete subValue [ metadata . options . discriminator . property ] ;
165
+ }
166
+ if ( this . transformationType === TransformationType . CLASS_TO_CLASS ) {
167
+ type = subValue . constructor ;
168
+ }
169
+ if ( this . transformationType === TransformationType . CLASS_TO_PLAIN ) {
170
+ subValue [ metadata . options . discriminator . property ] = metadata . options . discriminator . subTypes . find ( ( subType ) => subType . value === subValue . constructor ) . name ;
171
+ }
172
+ } else {
173
+ type = metadata ;
174
+ }
175
+ } else {
176
+ type = newType ;
177
+ }
164
178
isSubValueMap = isSubValueMap || metadata . reflectedType === Map ;
165
179
} else if ( this . options . targetMaps ) { // try to find a type in target maps
166
180
this . options . targetMaps
@@ -171,6 +185,7 @@ export class TransformOperationExecutor {
171
185
172
186
// if value is an array try to get its custom array type
173
187
const arrayType = value [ valueKey ] instanceof Array ? this . getReflectedType ( ( targetType as Function ) , propertyName ) : undefined ;
188
+
174
189
// const subValueKey = TransformationType === TransformationType.PLAIN_TO_CLASS && newKeyName ? newKeyName : key;
175
190
const subSource = source ? source [ valueKey ] : undefined ;
176
191
0 commit comments