UNPKG

22.9 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3var storage_1 = require("./storage");
4var 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 = {}));
10var TransformOperationExecutor = /** @class */ (function () {
11 // -------------------------------------------------------------------------
12 // Constructor
13 // -------------------------------------------------------------------------
14 function TransformOperationExecutor(transformationType, options) {
15 this.transformationType = transformationType;
16 this.options = options;
17 // -------------------------------------------------------------------------
18 // Private Properties
19 // -------------------------------------------------------------------------
20 this.recursionStack = new Set();
21 }
22 // -------------------------------------------------------------------------
23 // Public Methods
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 // try to guess the type
102 if (!targetType && value.constructor !== Object /* && TransformationType === TransformationType.CLASS_TO_PLAIN*/)
103 targetType = value.constructor;
104 if (!targetType && source)
105 targetType = source.constructor;
106 if (this.options.enableCircularCheck) {
107 // add transformed type to prevent circular references
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 // get a subvalue
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 // determine a type
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) { // try to find a type in target maps
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 // if we have no registererd type via the @Type() decorator then we check if we have any
199 // type declarations in reflect-metadata (type declaration is emited only if some decorator is added to the property.)
200 var reflectedType = Reflect.getMetadata("design:type", targetType.prototype, propertyName);
201 if (reflectedType) {
202 type = reflectedType;
203 }
204 }
205 }
206 // if value is an array try to get its custom array type
207 var arrayType_1 = Array.isArray(value[valueKey]) ? this_1.getReflectedType(targetType, propertyName) : undefined;
208 // const subValueKey = TransformationType === TransformationType.PLAIN_TO_CLASS && newKeyName ? newKeyName : key;
209 var subSource = source ? source[valueKey] : undefined;
210 // if its deserialization then type if required
211 // if we uncomment this types like string[] will not work
212 // if (this.transformationType === TransformationType.PLAIN_TO_CLASS && !type && subValue instanceof Object && !(subValue instanceof Date))
213 // throw new Error(`Cannot determine type for ${(targetType as any).name }.${propertyName}, did you forget to specify a @Type?`);
214 // if newValue is a source object that has method that match newKeyName then skip it
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)) // || TransformationType === TransformationType.CLASS_TO_CLASS
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 // Get original value
226 finalValue = value[transformKey];
227 // Apply custom transformation
228 finalValue = this_1.applyCustomTransformations(finalValue, targetType, transformKey, value, this_1.transformationType);
229 // If nothing change, it means no custom transformation was applied, so use the subValue.
230 finalValue = (value[transformKey] === finalValue) ? subValue : finalValue;
231 // Apply the default transformation
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 // traverse over keys
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 // apply versioning options
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 // apply grouping options
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 // preventing circular references
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 // determine exclusion strategy
313 var strategy = storage_1.defaultMetadataStorage.getStrategy(target);
314 if (strategy === "none")
315 strategy = this.options.strategy || "exposeAll"; // exposeAll is default strategy
316 // get all keys that need to expose
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 // add all exposed to list of keys
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 // exclude excluded properties
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 // apply versioning options
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 // apply grouping options
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 // exclude prefixed properties
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 // make sure we have unique keys
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}());
403exports.TransformOperationExecutor = TransformOperationExecutor;
404function instantiateArrayType(arrayType) {
405 var array = new arrayType();
406 if (!(array instanceof Set) && !("push" in array)) {
407 return [];
408 }
409 return array;
410}
411function testForBuffer() {
412 try {
413 Buffer;
414 return true;
415 }
416 catch (_a) { }
417 return false;
418}
419exports.testForBuffer = testForBuffer;
420
421//# sourceMappingURL=TransformOperationExecutor.js.map