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