1 | import { defaultMetadataStorage } from './storage';
|
2 | import { TransformationType } from './enums';
|
3 | import { getGlobal, isPromise } from './utils';
|
4 | function instantiateArrayType(arrayType) {
|
5 | var array = new arrayType();
|
6 | if (!(array instanceof Set) && !('push' in array)) {
|
7 | return [];
|
8 | }
|
9 | return array;
|
10 | }
|
11 | var TransformOperationExecutor = (function () {
|
12 |
|
13 |
|
14 |
|
15 | function TransformOperationExecutor(transformationType, options) {
|
16 | this.transformationType = transformationType;
|
17 | this.options = options;
|
18 |
|
19 |
|
20 |
|
21 | this.recursionStack = new Set();
|
22 | }
|
23 |
|
24 |
|
25 |
|
26 | TransformOperationExecutor.prototype.transform = function (source, value, targetType, arrayType, isMap, level) {
|
27 | var _this = this;
|
28 | if (level === void 0) { level = 0; }
|
29 | if (Array.isArray(value) || value instanceof Set) {
|
30 | var newValue_1 = arrayType && this.transformationType === TransformationType.PLAIN_TO_CLASS
|
31 | ? instantiateArrayType(arrayType)
|
32 | : [];
|
33 | value.forEach(function (subValue, index) {
|
34 | var subSource = source ? source[index] : undefined;
|
35 | if (!_this.options.enableCircularCheck || !_this.isCircular(subValue)) {
|
36 | var realTargetType = void 0;
|
37 | if (typeof targetType !== 'function' &&
|
38 | targetType &&
|
39 | targetType.options &&
|
40 | targetType.options.discriminator &&
|
41 | targetType.options.discriminator.property &&
|
42 | targetType.options.discriminator.subTypes) {
|
43 | if (_this.transformationType === TransformationType.PLAIN_TO_CLASS) {
|
44 | realTargetType = targetType.options.discriminator.subTypes.find(function (subType) {
|
45 | return subType.name === subValue[targetType.options.discriminator.property];
|
46 | });
|
47 | var options = { newObject: newValue_1, object: subValue, property: undefined };
|
48 | var newType = targetType.typeFunction(options);
|
49 | realTargetType === undefined ? (realTargetType = newType) : (realTargetType = realTargetType.value);
|
50 | if (!targetType.options.keepDiscriminatorProperty)
|
51 | 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(function (subType) { return subType.value === subValue.constructor; }).name;
|
58 | }
|
59 | }
|
60 | else {
|
61 | realTargetType = targetType;
|
62 | }
|
63 | var value_1 = _this.transform(subSource, subValue, realTargetType, undefined, subValue instanceof Map, level + 1);
|
64 | if (newValue_1 instanceof Set) {
|
65 | newValue_1.add(value_1);
|
66 | }
|
67 | else {
|
68 | newValue_1.push(value_1);
|
69 | }
|
70 | }
|
71 | else if (_this.transformationType === TransformationType.CLASS_TO_CLASS) {
|
72 | if (newValue_1 instanceof Set) {
|
73 | newValue_1.add(subValue);
|
74 | }
|
75 | else {
|
76 | newValue_1.push(subValue);
|
77 | }
|
78 | }
|
79 | });
|
80 | return newValue_1;
|
81 | }
|
82 | else if (targetType === String && !isMap) {
|
83 | if (value === null || value === undefined)
|
84 | return value;
|
85 | return String(value);
|
86 | }
|
87 | else if (targetType === Number && !isMap) {
|
88 | if (value === null || value === undefined)
|
89 | return value;
|
90 | return Number(value);
|
91 | }
|
92 | else if (targetType === Boolean && !isMap) {
|
93 | if (value === null || value === undefined)
|
94 | return value;
|
95 | return Boolean(value);
|
96 | }
|
97 | else if ((targetType === Date || value instanceof Date) && !isMap) {
|
98 | if (value instanceof Date) {
|
99 | return new Date(value.valueOf());
|
100 | }
|
101 | if (value === null || value === undefined)
|
102 | return value;
|
103 | return new Date(value);
|
104 | }
|
105 | else if (!!getGlobal().Buffer && (targetType === Buffer || value instanceof Buffer) && !isMap) {
|
106 | if (value === null || value === undefined)
|
107 | return value;
|
108 | return Buffer.from(value);
|
109 | }
|
110 | else if (isPromise(value) && !isMap) {
|
111 | return new Promise(function (resolve, reject) {
|
112 | value.then(function (data) { return resolve(_this.transform(undefined, data, targetType, undefined, undefined, level + 1)); }, reject);
|
113 | });
|
114 | }
|
115 | else if (!isMap && value !== null && typeof value === 'object' && typeof value.then === 'function') {
|
116 |
|
117 |
|
118 | return value;
|
119 | }
|
120 | else if (typeof value === 'object' && value !== null) {
|
121 |
|
122 | if (!targetType && value.constructor !== Object )
|
123 | targetType = value.constructor;
|
124 | if (!targetType && source)
|
125 | targetType = source.constructor;
|
126 | if (this.options.enableCircularCheck) {
|
127 |
|
128 | this.recursionStack.add(value);
|
129 | }
|
130 | var keys = this.getKeys(targetType, value, isMap);
|
131 | var newValue = source ? source : {};
|
132 | if (!source &&
|
133 | (this.transformationType === TransformationType.PLAIN_TO_CLASS ||
|
134 | this.transformationType === TransformationType.CLASS_TO_CLASS)) {
|
135 | if (isMap) {
|
136 | newValue = new Map();
|
137 | }
|
138 | else if (targetType) {
|
139 | newValue = new targetType();
|
140 | }
|
141 | else {
|
142 | newValue = {};
|
143 | }
|
144 | }
|
145 | var _loop_1 = function (key) {
|
146 | if (key === '__proto__' || key === 'constructor') {
|
147 | return "continue";
|
148 | }
|
149 | var valueKey = key;
|
150 | var newValueKey = key, propertyName = key;
|
151 | if (!this_1.options.ignoreDecorators && targetType) {
|
152 | if (this_1.transformationType === TransformationType.PLAIN_TO_CLASS) {
|
153 | var exposeMetadata = defaultMetadataStorage.findExposeMetadataByCustomName(targetType, key);
|
154 | if (exposeMetadata) {
|
155 | propertyName = exposeMetadata.propertyName;
|
156 | newValueKey = exposeMetadata.propertyName;
|
157 | }
|
158 | }
|
159 | else if (this_1.transformationType === TransformationType.CLASS_TO_PLAIN ||
|
160 | this_1.transformationType === TransformationType.CLASS_TO_CLASS) {
|
161 | var exposeMetadata = defaultMetadataStorage.findExposeMetadata(targetType, key);
|
162 | if (exposeMetadata && exposeMetadata.options && exposeMetadata.options.name) {
|
163 | newValueKey = exposeMetadata.options.name;
|
164 | }
|
165 | }
|
166 | }
|
167 |
|
168 | var subValue = undefined;
|
169 | if (value instanceof Map) {
|
170 | subValue = value.get(valueKey);
|
171 | }
|
172 | else if (value[valueKey] instanceof Function) {
|
173 | subValue = value[valueKey]();
|
174 | }
|
175 | else {
|
176 | subValue = value[valueKey];
|
177 | }
|
178 |
|
179 | var type = undefined, isSubValueMap = subValue instanceof Map;
|
180 | if (targetType && isMap) {
|
181 | type = targetType;
|
182 | }
|
183 | else if (targetType) {
|
184 | var metadata_1 = defaultMetadataStorage.findTypeMetadata(targetType, propertyName);
|
185 | if (metadata_1) {
|
186 | var options = { newObject: newValue, object: value, property: propertyName };
|
187 | var newType = metadata_1.typeFunction ? metadata_1.typeFunction(options) : metadata_1.reflectedType;
|
188 | if (metadata_1.options &&
|
189 | metadata_1.options.discriminator &&
|
190 | metadata_1.options.discriminator.property &&
|
191 | metadata_1.options.discriminator.subTypes) {
|
192 | if (!(value[valueKey] instanceof Array)) {
|
193 | if (this_1.transformationType === TransformationType.PLAIN_TO_CLASS) {
|
194 | type = metadata_1.options.discriminator.subTypes.find(function (subType) {
|
195 | if (subValue && subValue instanceof Object && metadata_1.options.discriminator.property in subValue) {
|
196 | return subType.name === subValue[metadata_1.options.discriminator.property];
|
197 | }
|
198 | });
|
199 | type === undefined ? (type = newType) : (type = type.value);
|
200 | if (!metadata_1.options.keepDiscriminatorProperty) {
|
201 | if (subValue && subValue instanceof Object && metadata_1.options.discriminator.property in subValue) {
|
202 | delete subValue[metadata_1.options.discriminator.property];
|
203 | }
|
204 | }
|
205 | }
|
206 | if (this_1.transformationType === TransformationType.CLASS_TO_CLASS) {
|
207 | type = subValue.constructor;
|
208 | }
|
209 | if (this_1.transformationType === TransformationType.CLASS_TO_PLAIN) {
|
210 | subValue[metadata_1.options.discriminator.property] = metadata_1.options.discriminator.subTypes.find(function (subType) { return subType.value === subValue.constructor; }).name;
|
211 | }
|
212 | }
|
213 | else {
|
214 | type = metadata_1;
|
215 | }
|
216 | }
|
217 | else {
|
218 | type = newType;
|
219 | }
|
220 | isSubValueMap = isSubValueMap || metadata_1.reflectedType === Map;
|
221 | }
|
222 | else if (this_1.options.targetMaps) {
|
223 |
|
224 | this_1.options.targetMaps
|
225 | .filter(function (map) { return map.target === targetType && !!map.properties[propertyName]; })
|
226 | .forEach(function (map) { return (type = map.properties[propertyName]); });
|
227 | }
|
228 | else if (this_1.options.enableImplicitConversion &&
|
229 | this_1.transformationType === TransformationType.PLAIN_TO_CLASS) {
|
230 |
|
231 |
|
232 | var reflectedType = Reflect.getMetadata('design:type', targetType.prototype, propertyName);
|
233 | if (reflectedType) {
|
234 | type = reflectedType;
|
235 | }
|
236 | }
|
237 | }
|
238 |
|
239 | var arrayType_1 = Array.isArray(value[valueKey])
|
240 | ? this_1.getReflectedType(targetType, propertyName)
|
241 | : undefined;
|
242 |
|
243 | var subSource = source ? source[valueKey] : undefined;
|
244 |
|
245 |
|
246 |
|
247 |
|
248 |
|
249 | if (newValue.constructor.prototype) {
|
250 | var descriptor = Object.getOwnPropertyDescriptor(newValue.constructor.prototype, newValueKey);
|
251 | if ((this_1.transformationType === TransformationType.PLAIN_TO_CLASS ||
|
252 | this_1.transformationType === TransformationType.CLASS_TO_CLASS) &&
|
253 |
|
254 | ((descriptor && !descriptor.set) || newValue[newValueKey] instanceof Function))
|
255 | return "continue";
|
256 | }
|
257 | if (!this_1.options.enableCircularCheck || !this_1.isCircular(subValue)) {
|
258 | var transformKey = this_1.transformationType === TransformationType.PLAIN_TO_CLASS ? newValueKey : key;
|
259 | var finalValue = void 0;
|
260 | if (this_1.transformationType === TransformationType.CLASS_TO_PLAIN) {
|
261 |
|
262 | finalValue = value[transformKey];
|
263 |
|
264 | finalValue = this_1.applyCustomTransformations(finalValue, targetType, transformKey, value, this_1.transformationType);
|
265 |
|
266 | finalValue = value[transformKey] === finalValue ? subValue : finalValue;
|
267 |
|
268 | finalValue = this_1.transform(subSource, finalValue, type, arrayType_1, isSubValueMap, level + 1);
|
269 | }
|
270 | else {
|
271 | if (subValue === undefined && this_1.options.exposeDefaultValues) {
|
272 |
|
273 | finalValue = newValue[newValueKey];
|
274 | }
|
275 | else {
|
276 | finalValue = this_1.transform(subSource, subValue, type, arrayType_1, isSubValueMap, level + 1);
|
277 | finalValue = this_1.applyCustomTransformations(finalValue, targetType, transformKey, value, this_1.transformationType);
|
278 | }
|
279 | }
|
280 | if (finalValue !== undefined || this_1.options.exposeUnsetFields) {
|
281 | if (newValue instanceof Map) {
|
282 | newValue.set(newValueKey, finalValue);
|
283 | }
|
284 | else {
|
285 | newValue[newValueKey] = finalValue;
|
286 | }
|
287 | }
|
288 | }
|
289 | else if (this_1.transformationType === TransformationType.CLASS_TO_CLASS) {
|
290 | var finalValue = subValue;
|
291 | finalValue = this_1.applyCustomTransformations(finalValue, targetType, key, value, this_1.transformationType);
|
292 | if (finalValue !== undefined || this_1.options.exposeUnsetFields) {
|
293 | if (newValue instanceof Map) {
|
294 | newValue.set(newValueKey, finalValue);
|
295 | }
|
296 | else {
|
297 | newValue[newValueKey] = finalValue;
|
298 | }
|
299 | }
|
300 | }
|
301 | };
|
302 | var this_1 = this;
|
303 |
|
304 | for (var _i = 0, keys_1 = keys; _i < keys_1.length; _i++) {
|
305 | var key = keys_1[_i];
|
306 | _loop_1(key);
|
307 | }
|
308 | if (this.options.enableCircularCheck) {
|
309 | this.recursionStack.delete(value);
|
310 | }
|
311 | return newValue;
|
312 | }
|
313 | else {
|
314 | return value;
|
315 | }
|
316 | };
|
317 | TransformOperationExecutor.prototype.applyCustomTransformations = function (value, target, key, obj, transformationType) {
|
318 | var _this = this;
|
319 | var metadatas = defaultMetadataStorage.findTransformMetadatas(target, key, this.transformationType);
|
320 |
|
321 | if (this.options.version !== undefined) {
|
322 | metadatas = metadatas.filter(function (metadata) {
|
323 | if (!metadata.options)
|
324 | return true;
|
325 | return _this.checkVersion(metadata.options.since, metadata.options.until);
|
326 | });
|
327 | }
|
328 |
|
329 | if (this.options.groups && this.options.groups.length) {
|
330 | metadatas = metadatas.filter(function (metadata) {
|
331 | if (!metadata.options)
|
332 | return true;
|
333 | return _this.checkGroups(metadata.options.groups);
|
334 | });
|
335 | }
|
336 | else {
|
337 | metadatas = metadatas.filter(function (metadata) {
|
338 | return !metadata.options || !metadata.options.groups || !metadata.options.groups.length;
|
339 | });
|
340 | }
|
341 | metadatas.forEach(function (metadata) {
|
342 | value = metadata.transformFn({ value: value, key: key, obj: obj, type: transformationType, options: _this.options });
|
343 | });
|
344 | return value;
|
345 | };
|
346 |
|
347 | TransformOperationExecutor.prototype.isCircular = function (object) {
|
348 | return this.recursionStack.has(object);
|
349 | };
|
350 | TransformOperationExecutor.prototype.getReflectedType = function (target, propertyName) {
|
351 | if (!target)
|
352 | return undefined;
|
353 | var meta = defaultMetadataStorage.findTypeMetadata(target, propertyName);
|
354 | return meta ? meta.reflectedType : undefined;
|
355 | };
|
356 | TransformOperationExecutor.prototype.getKeys = function (target, object, isMap) {
|
357 | var _this = this;
|
358 |
|
359 | var strategy = defaultMetadataStorage.getStrategy(target);
|
360 | if (strategy === 'none')
|
361 | strategy = this.options.strategy || 'exposeAll';
|
362 |
|
363 | var keys = [];
|
364 | if (strategy === 'exposeAll' || isMap) {
|
365 | if (object instanceof Map) {
|
366 | keys = Array.from(object.keys());
|
367 | }
|
368 | else {
|
369 | keys = Object.keys(object);
|
370 | }
|
371 | }
|
372 | if (isMap) {
|
373 |
|
374 | return keys;
|
375 | }
|
376 | if (!this.options.ignoreDecorators && target) {
|
377 |
|
378 | var exposedProperties = defaultMetadataStorage.getExposedProperties(target, this.transformationType);
|
379 | if (this.transformationType === TransformationType.PLAIN_TO_CLASS) {
|
380 | exposedProperties = exposedProperties.map(function (key) {
|
381 | var exposeMetadata = defaultMetadataStorage.findExposeMetadata(target, key);
|
382 | if (exposeMetadata && exposeMetadata.options && exposeMetadata.options.name) {
|
383 | return exposeMetadata.options.name;
|
384 | }
|
385 | return key;
|
386 | });
|
387 | }
|
388 | if (this.options.excludeExtraneousValues) {
|
389 | keys = exposedProperties;
|
390 | }
|
391 | else {
|
392 | keys = keys.concat(exposedProperties);
|
393 | }
|
394 |
|
395 | var excludedProperties_1 = defaultMetadataStorage.getExcludedProperties(target, this.transformationType);
|
396 | if (excludedProperties_1.length > 0) {
|
397 | keys = keys.filter(function (key) {
|
398 | return !excludedProperties_1.includes(key);
|
399 | });
|
400 | }
|
401 |
|
402 | if (this.options.version !== undefined) {
|
403 | keys = keys.filter(function (key) {
|
404 | var exposeMetadata = defaultMetadataStorage.findExposeMetadata(target, key);
|
405 | if (!exposeMetadata || !exposeMetadata.options)
|
406 | return true;
|
407 | return _this.checkVersion(exposeMetadata.options.since, exposeMetadata.options.until);
|
408 | });
|
409 | }
|
410 |
|
411 | if (this.options.groups && this.options.groups.length) {
|
412 | keys = keys.filter(function (key) {
|
413 | var exposeMetadata = defaultMetadataStorage.findExposeMetadata(target, key);
|
414 | if (!exposeMetadata || !exposeMetadata.options)
|
415 | return true;
|
416 | return _this.checkGroups(exposeMetadata.options.groups);
|
417 | });
|
418 | }
|
419 | else {
|
420 | keys = keys.filter(function (key) {
|
421 | var exposeMetadata = defaultMetadataStorage.findExposeMetadata(target, key);
|
422 | return (!exposeMetadata ||
|
423 | !exposeMetadata.options ||
|
424 | !exposeMetadata.options.groups ||
|
425 | !exposeMetadata.options.groups.length);
|
426 | });
|
427 | }
|
428 | }
|
429 |
|
430 | if (this.options.excludePrefixes && this.options.excludePrefixes.length) {
|
431 | keys = keys.filter(function (key) {
|
432 | return _this.options.excludePrefixes.every(function (prefix) {
|
433 | return key.substr(0, prefix.length) !== prefix;
|
434 | });
|
435 | });
|
436 | }
|
437 |
|
438 | keys = keys.filter(function (key, index, self) {
|
439 | return self.indexOf(key) === index;
|
440 | });
|
441 | return keys;
|
442 | };
|
443 | TransformOperationExecutor.prototype.checkVersion = function (since, until) {
|
444 | var decision = true;
|
445 | if (decision && since)
|
446 | decision = this.options.version >= since;
|
447 | if (decision && until)
|
448 | decision = this.options.version < until;
|
449 | return decision;
|
450 | };
|
451 | TransformOperationExecutor.prototype.checkGroups = function (groups) {
|
452 | if (!groups)
|
453 | return true;
|
454 | return this.options.groups.some(function (optionGroup) { return groups.includes(optionGroup); });
|
455 | };
|
456 | return TransformOperationExecutor;
|
457 | }());
|
458 | export { TransformOperationExecutor };
|
459 |
|
\ | No newline at end of file |