1
1
import { ClassTransformOptions } from "./ClassTransformOptions" ;
2
2
import { defaultMetadataStorage } from "./storage" ;
3
3
import { TypeOptions } from "./metadata/ExposeExcludeOptions" ;
4
- import { ExposeMetadata } from "./metadata/ExposeMetadata" ;
5
4
6
- export type TransformationType = "plainToClass" | "classToPlain" | "classToClass" ;
5
+ export enum TransformationType {
6
+ PLAIN_TO_CLASS ,
7
+ CLASS_TO_PLAIN ,
8
+ CLASS_TO_CLASS
9
+ }
7
10
8
11
export class TransformOperationExecutor {
9
12
10
13
// -------------------------------------------------------------------------
11
14
// Private Properties
12
15
// -------------------------------------------------------------------------
13
16
14
- private transformedTypesMap = new Map < Object , { level : number , object : Object } > ( ) ;
17
+ private transformedTypesMap = new Map < Object , { level : number , object : Object } > ( ) ;
15
18
16
19
// -------------------------------------------------------------------------
17
20
// Constructor
@@ -33,7 +36,7 @@ export class TransformOperationExecutor {
33
36
level : number = 0 ) {
34
37
35
38
if ( value instanceof Array || value instanceof Set ) {
36
- const newValue = arrayType && this . transformationType === "plainToClass" ? new ( arrayType as any ) ( ) : [ ] ;
39
+ const newValue = arrayType && this . transformationType === TransformationType . PLAIN_TO_CLASS ? new ( arrayType as any ) ( ) : [ ] ;
37
40
( value as any [ ] ) . forEach ( ( subValue , index ) => {
38
41
const subSource = source ? source [ index ] : undefined ;
39
42
if ( ! this . options . enableCircularCheck || ! this . isCircular ( subValue , level ) ) {
@@ -43,7 +46,7 @@ export class TransformOperationExecutor {
43
46
} else {
44
47
newValue . push ( value ) ;
45
48
}
46
- } else if ( this . transformationType === "classToClass" ) {
49
+ } else if ( this . transformationType === TransformationType . CLASS_TO_CLASS ) {
47
50
if ( newValue instanceof Set ) {
48
51
newValue . add ( subValue ) ;
49
52
} else {
@@ -74,17 +77,17 @@ export class TransformOperationExecutor {
74
77
} else if ( value instanceof Object ) {
75
78
76
79
// try to guess the type
77
- if ( ! targetType && value . constructor !== Object /* && operationType === "classToPlain" */ ) targetType = value . constructor ;
80
+ if ( ! targetType && value . constructor !== Object /* && TransformationType === TransformationType.CLASS_TO_PLAIN */ ) targetType = value . constructor ;
78
81
if ( ! targetType && source ) targetType = source . constructor ;
79
82
80
83
if ( this . options . enableCircularCheck ) {
81
84
// add transformed type to prevent circular references
82
- this . transformedTypesMap . set ( value , { level : level , object : value } ) ;
85
+ this . transformedTypesMap . set ( value , { level : level , object : value } ) ;
83
86
}
84
87
85
88
const keys = this . getKeys ( targetType , value ) ;
86
89
let newValue : any = source ? source : { } ;
87
- if ( ! source && ( this . transformationType === "plainToClass" || this . transformationType === "classToClass" ) ) {
90
+ if ( ! source && ( this . transformationType === TransformationType . PLAIN_TO_CLASS || this . transformationType === TransformationType . CLASS_TO_CLASS ) ) {
88
91
if ( isMap ) {
89
92
newValue = new Map ( ) ;
90
93
} else if ( targetType ) {
@@ -99,14 +102,14 @@ export class TransformOperationExecutor {
99
102
100
103
let valueKey = key , newValueKey = key , propertyName = key ;
101
104
if ( ! this . options . ignoreDecorators && targetType ) {
102
- if ( this . transformationType === "plainToClass" ) {
105
+ if ( this . transformationType === TransformationType . PLAIN_TO_CLASS ) {
103
106
const exposeMetadata = defaultMetadataStorage . findExposeMetadataByCustomName ( targetType , key ) ;
104
107
if ( exposeMetadata ) {
105
108
propertyName = exposeMetadata . propertyName ;
106
109
newValueKey = exposeMetadata . propertyName ;
107
110
}
108
111
109
- } else if ( this . transformationType === "classToPlain" || this . transformationType === "classToClass" ) {
112
+ } else if ( this . transformationType === TransformationType . CLASS_TO_PLAIN || this . transformationType === TransformationType . CLASS_TO_CLASS ) {
110
113
const exposeMetadata = defaultMetadataStorage . findExposeMetadata ( targetType , key ) ;
111
114
if ( exposeMetadata && exposeMetadata . options && exposeMetadata . options . name )
112
115
newValueKey = exposeMetadata . options . name ;
@@ -131,7 +134,7 @@ export class TransformOperationExecutor {
131
134
} else if ( targetType ) {
132
135
const metadata = defaultMetadataStorage . findTypeMetadata ( targetType , propertyName ) ;
133
136
if ( metadata ) {
134
- const options : TypeOptions = { newObject : newValue , object : value , property : propertyName } ;
137
+ const options : TypeOptions = { newObject : newValue , object : value , property : propertyName } ;
135
138
type = metadata . typeFunction ( options ) ;
136
139
isSubValueMap = isSubValueMap || metadata . reflectedType === Map ;
137
140
} else if ( this . options . targetMaps ) { // try to find a type in target maps
@@ -143,34 +146,34 @@ export class TransformOperationExecutor {
143
146
144
147
// if value is an array try to get its custom array type
145
148
const arrayType = value [ valueKey ] instanceof Array ? this . getReflectedType ( targetType , propertyName ) : undefined ;
146
- // const subValueKey = operationType === "plainToClass" && newKeyName ? newKeyName : key;
149
+ // const subValueKey = TransformationType === TransformationType.PLAIN_TO_CLASS && newKeyName ? newKeyName : key;
147
150
const subSource = source ? source [ valueKey ] : undefined ;
148
151
149
152
// if its deserialization then type if required
150
153
// if we uncomment this types like string[] will not work
151
- // if (this.transformationType === "plainToClass" && !type && subValue instanceof Object && !(subValue instanceof Date))
154
+ // if (this.transformationType === TransformationType.PLAIN_TO_CLASS && !type && subValue instanceof Object && !(subValue instanceof Date))
152
155
// throw new Error(`Cannot determine type for ${(targetType as any).name }.${propertyName}, did you forget to specify a @Type?`);
153
156
154
157
// if newValue is a source object that has method that match newKeyName then skip it
155
158
if ( newValue . constructor . prototype ) {
156
159
const descriptor = Object . getOwnPropertyDescriptor ( newValue . constructor . prototype , newValueKey ) ;
157
- if ( ( this . transformationType === "plainToClass" || this . transformationType === "classToClass" )
158
- && ( newValue [ newValueKey ] instanceof Function || ( descriptor && ! descriptor . set ) ) ) // || operationType === "classToClass"
160
+ if ( ( this . transformationType === TransformationType . PLAIN_TO_CLASS || this . transformationType === TransformationType . CLASS_TO_CLASS )
161
+ && ( newValue [ newValueKey ] instanceof Function || ( descriptor && ! descriptor . set ) ) ) // || TransformationType === TransformationType.CLASS_TO_CLASS
159
162
continue ;
160
163
}
161
164
162
165
if ( ! this . options . enableCircularCheck || ! this . isCircular ( subValue , level ) ) {
163
- let transformKey = this . transformationType === "plainToClass" ? newValueKey : key ;
166
+ let transformKey = this . transformationType === TransformationType . PLAIN_TO_CLASS ? newValueKey : key ;
164
167
let finalValue = this . transform ( subSource , subValue , type , arrayType , isSubValueMap , level + 1 ) ;
165
- finalValue = this . applyCustomTransformations ( finalValue , targetType , transformKey ) ;
168
+ finalValue = this . applyCustomTransformations ( finalValue , targetType , transformKey , value , this . transformationType ) ;
166
169
if ( newValue instanceof Map ) {
167
170
newValue . set ( newValueKey , finalValue ) ;
168
171
} else {
169
172
newValue [ newValueKey ] = finalValue ;
170
173
}
171
- } else if ( this . transformationType === "classToClass" ) {
174
+ } else if ( this . transformationType === TransformationType . CLASS_TO_CLASS ) {
172
175
let finalValue = subValue ;
173
- finalValue = this . applyCustomTransformations ( finalValue , targetType , key ) ;
176
+ finalValue = this . applyCustomTransformations ( finalValue , targetType , key , value , this . transformationType ) ;
174
177
if ( newValue instanceof Map ) {
175
178
newValue . set ( newValueKey , finalValue ) ;
176
179
} else {
@@ -186,7 +189,7 @@ export class TransformOperationExecutor {
186
189
}
187
190
}
188
191
189
- private applyCustomTransformations ( value : any , target : Function , key : string ) {
192
+ private applyCustomTransformations ( value : any , target : Function , key : string , obj : any , transformationType : TransformationType ) {
190
193
let metadatas = defaultMetadataStorage . findTransformMetadatas ( target , key , this . transformationType ) ;
191
194
192
195
// apply versioning options
@@ -209,14 +212,12 @@ export class TransformOperationExecutor {
209
212
} ) ;
210
213
} else {
211
214
metadatas = metadatas . filter ( metadata => {
212
- return ! metadata . options ||
213
- ! metadata . options . groups ||
214
- ! metadata . options . groups . length ;
215
+ return ! metadata . options || ! metadata . options . groups || ! metadata . options . groups . length ;
215
216
} ) ;
216
217
}
217
218
218
219
metadatas . forEach ( metadata => {
219
- value = metadata . transformFn ( value ) ;
220
+ value = metadata . transformFn ( value , obj , transformationType ) ;
220
221
} ) ;
221
222
222
223
return value ;
@@ -255,7 +256,7 @@ export class TransformOperationExecutor {
255
256
256
257
// add all exposed to list of keys
257
258
let exposedProperties = defaultMetadataStorage . getExposedProperties ( target , this . transformationType ) ;
258
- if ( this . transformationType === "plainToClass" ) {
259
+ if ( this . transformationType === TransformationType . PLAIN_TO_CLASS ) {
259
260
exposedProperties = exposedProperties . map ( key => {
260
261
const exposeMetadata = defaultMetadataStorage . findExposeMetadata ( target , key ) ;
261
262
if ( exposeMetadata && exposeMetadata . options && exposeMetadata . options . name ) {
@@ -298,10 +299,7 @@ export class TransformOperationExecutor {
298
299
} else {
299
300
keys = keys . filter ( key => {
300
301
const exposeMetadata = defaultMetadataStorage . findExposeMetadata ( target , key ) ;
301
- return ! exposeMetadata ||
302
- ! exposeMetadata . options ||
303
- ! exposeMetadata . options . groups ||
304
- ! exposeMetadata . options . groups . length ;
302
+ return ! exposeMetadata || ! exposeMetadata . options || ! exposeMetadata . options . groups || ! exposeMetadata . options . groups . length ;
305
303
} ) ;
306
304
}
307
305
}
@@ -338,4 +336,4 @@ export class TransformOperationExecutor {
338
336
return this . options . groups . some ( optionGroup => groups . indexOf ( optionGroup ) !== - 1 ) ;
339
337
}
340
338
341
- }
339
+ }
0 commit comments