UNPKG

15.2 kBJavaScriptView Raw
1"use strict";
2var index_1 = require("./index");
3var TransformOperationExecutor = (function () {
4 // -------------------------------------------------------------------------
5 // Constructor
6 // -------------------------------------------------------------------------
7 function TransformOperationExecutor(transformationType, options) {
8 this.transformationType = transformationType;
9 this.options = options;
10 // -------------------------------------------------------------------------
11 // Private Properties
12 // -------------------------------------------------------------------------
13 this.transformedTypes = [];
14 }
15 // -------------------------------------------------------------------------
16 // Public Methods
17 // -------------------------------------------------------------------------
18 TransformOperationExecutor.prototype.transform = function (source, value, targetType, arrayType, isMap, level) {
19 var _this = this;
20 if (level === void 0) { level = 0; }
21 if (value instanceof Array || value instanceof Set) {
22 var newValue_1 = arrayType && this.transformationType === "plainToClass" ? new arrayType() : [];
23 value.forEach(function (subValue, index) {
24 var subSource = source ? source[index] : undefined;
25 if (!_this.isCircular(subValue, level)) {
26 var value_1 = _this.transform(subSource, subValue, targetType, undefined, subValue instanceof Map, level + 1);
27 if (newValue_1 instanceof Set) {
28 newValue_1.add(value_1);
29 }
30 else {
31 newValue_1.push(value_1);
32 }
33 }
34 else if (_this.transformationType === "classToClass") {
35 if (newValue_1 instanceof Set) {
36 newValue_1.add(subValue);
37 }
38 else {
39 newValue_1.push(subValue);
40 }
41 }
42 });
43 return newValue_1;
44 }
45 else if (targetType === String && !isMap) {
46 return String(value);
47 }
48 else if (targetType === Number && !isMap) {
49 return Number(value);
50 }
51 else if (targetType === Boolean && !isMap) {
52 return Boolean(value);
53 }
54 else if ((targetType === Date || value instanceof Date) && !isMap) {
55 if (value instanceof Date) {
56 return new Date(value.valueOf());
57 }
58 return new Date(value);
59 }
60 else if (value instanceof Object) {
61 // try to guess the type
62 if (!targetType && value.constructor !== Object /* && operationType === "classToPlain"*/)
63 targetType = value.constructor;
64 if (!targetType && source)
65 targetType = source.constructor;
66 // add transformed type to prevent circular references
67 this.transformedTypes.push({ level: level, object: value });
68 var keys = this.getKeys(targetType, value);
69 var newValue = source ? source : {};
70 if (!source && (this.transformationType === "plainToClass" || this.transformationType === "classToClass")) {
71 if (isMap) {
72 newValue = new Map();
73 }
74 else if (targetType) {
75 newValue = new targetType();
76 }
77 else {
78 newValue = {};
79 }
80 }
81 // traverse over keys
82 var _loop_1 = function(key) {
83 var valueKey = key, newValueKey = key, propertyName = key;
84 if (!this_1.options.ignoreDecorators && targetType) {
85 if (this_1.transformationType === "plainToClass") {
86 var exposeMetadata = index_1.defaultMetadataStorage.findExposeMetadataByCustomName(targetType, key);
87 if (exposeMetadata) {
88 propertyName = exposeMetadata.propertyName;
89 newValueKey = exposeMetadata.propertyName;
90 }
91 }
92 else if (this_1.transformationType === "classToPlain" || this_1.transformationType === "classToClass") {
93 var exposeMetadata = index_1.defaultMetadataStorage.findExposeMetadata(targetType, key);
94 if (exposeMetadata && exposeMetadata.options && exposeMetadata.options.name)
95 newValueKey = exposeMetadata.options.name;
96 }
97 }
98 // get a subvalue
99 var subValue = undefined;
100 if (value instanceof Map) {
101 subValue = value.get(valueKey);
102 }
103 else if (value[valueKey] instanceof Function) {
104 subValue = value[valueKey]();
105 }
106 else {
107 subValue = value[valueKey];
108 }
109 // determine a type
110 var type = undefined, isSubValueMap = subValue instanceof Map;
111 if (targetType && isMap) {
112 type = targetType;
113 }
114 else if (targetType) {
115 var metadata = index_1.defaultMetadataStorage.findTypeMetadata(targetType, propertyName);
116 if (metadata) {
117 var options = { newObject: newValue, object: value, property: propertyName };
118 type = metadata.typeFunction(options);
119 isSubValueMap = isSubValueMap || metadata.reflectedType === Map;
120 }
121 else if (this_1.options.targetMaps) {
122 this_1.options.targetMaps
123 .filter(function (map) { return map.target === targetType && !!map.properties[propertyName]; })
124 .forEach(function (map) { return type = map.properties[propertyName]; });
125 }
126 }
127 // if value is an array try to get its custom array type
128 var arrayType_1 = value[valueKey] instanceof Array ? this_1.getReflectedType(targetType, propertyName) : undefined;
129 // const subValueKey = operationType === "plainToClass" && newKeyName ? newKeyName : key;
130 var subSource = source ? source[valueKey] : undefined;
131 // if its deserialization then type if required
132 // if we uncomment this types like string[] will not work
133 // if (this.transformationType === "plainToClass" && !type && subValue instanceof Object && !(subValue instanceof Date))
134 // throw new Error(`Cannot determine type for ${(targetType as any).name }.${propertyName}, did you forget to specify a @Type?`);
135 // if newValue is a source object that has method that match newKeyName then skip it
136 if (newValue.constructor.prototype) {
137 var descriptor = Object.getOwnPropertyDescriptor(newValue.constructor.prototype, newValueKey);
138 if ((this_1.transformationType === "plainToClass" || this_1.transformationType === "classToClass")
139 && (newValue[newValueKey] instanceof Function || (descriptor && !descriptor.set)))
140 return "continue";
141 }
142 if (!this_1.isCircular(subValue, level)) {
143 var finalValue = this_1.transform(subSource, subValue, type, arrayType_1, isSubValueMap, level + 1);
144 finalValue = this_1.applyCustomTransformations(finalValue, targetType, key);
145 if (newValue instanceof Map) {
146 newValue.set(newValueKey, finalValue);
147 }
148 else {
149 newValue[newValueKey] = finalValue;
150 }
151 }
152 else if (this_1.transformationType === "classToClass") {
153 var finalValue = subValue;
154 finalValue = this_1.applyCustomTransformations(finalValue, targetType, key);
155 if (newValue instanceof Map) {
156 newValue.set(newValueKey, finalValue);
157 }
158 else {
159 newValue[newValueKey] = finalValue;
160 }
161 }
162 };
163 var this_1 = this;
164 for (var _i = 0, keys_1 = keys; _i < keys_1.length; _i++) {
165 var key = keys_1[_i];
166 var state_1 = _loop_1(key);
167 if (state_1 === "continue") continue;
168 }
169 return newValue;
170 }
171 else {
172 return value;
173 }
174 };
175 TransformOperationExecutor.prototype.applyCustomTransformations = function (value, target, key) {
176 var _this = this;
177 var metadatas = index_1.defaultMetadataStorage.findTransformMetadatas(target, key, this.transformationType);
178 // apply versioning options
179 if (this.options.version !== undefined) {
180 metadatas = metadatas.filter(function (metadata) {
181 if (!metadata.options)
182 return true;
183 return _this.checkVersion(metadata.options.since, metadata.options.until);
184 });
185 }
186 // apply grouping options
187 if (this.options.groups && this.options.groups.length) {
188 metadatas = metadatas.filter(function (metadata) {
189 if (!metadata.options)
190 return true;
191 return _this.checkGroups(metadata.options.groups);
192 });
193 }
194 else {
195 metadatas = metadatas.filter(function (metadata) {
196 return !metadata.options ||
197 !metadata.options.groups ||
198 !metadata.options.groups.length;
199 });
200 }
201 metadatas.forEach(function (metadata) {
202 value = metadata.transformFn(value);
203 });
204 return value;
205 };
206 // preventing circular references
207 TransformOperationExecutor.prototype.isCircular = function (object, level) {
208 return !!this.transformedTypes.find(function (transformed) { return transformed.object === object && transformed.level < level; });
209 };
210 TransformOperationExecutor.prototype.getReflectedType = function (target, propertyName) {
211 if (!target)
212 return undefined;
213 var meta = index_1.defaultMetadataStorage.findTypeMetadata(target, propertyName);
214 return meta ? meta.reflectedType : undefined;
215 };
216 TransformOperationExecutor.prototype.getKeys = function (target, object) {
217 var _this = this;
218 // determine exclusion strategy
219 var strategy = index_1.defaultMetadataStorage.getStrategy(target);
220 if (strategy === "none")
221 strategy = this.options.strategy || "exposeAll"; // exposeAll is default strategy
222 // get all keys that need to expose
223 var keys = [];
224 if (strategy === "exposeAll") {
225 if (object instanceof Map) {
226 keys = Array.from(object.keys());
227 }
228 else {
229 keys = Object.keys(object);
230 }
231 }
232 if (!this.options.ignoreDecorators && target) {
233 // add all exposed to list of keys
234 var exposedProperties = index_1.defaultMetadataStorage.getExposedProperties(target, this.transformationType);
235 if (this.transformationType === "plainToClass") {
236 exposedProperties = exposedProperties.map(function (key) {
237 var exposeMetadata = index_1.defaultMetadataStorage.findExposeMetadata(target, key);
238 if (exposeMetadata && exposeMetadata.options && exposeMetadata.options.name) {
239 return exposeMetadata.options.name;
240 }
241 return key;
242 });
243 }
244 keys = keys.concat(exposedProperties);
245 // exclude excluded properties
246 var excludedProperties_1 = index_1.defaultMetadataStorage.getExcludedProperties(target, this.transformationType);
247 if (excludedProperties_1.length > 0) {
248 keys = keys.filter(function (key) {
249 return excludedProperties_1.indexOf(key) === -1;
250 });
251 }
252 // apply versioning options
253 if (this.options.version !== undefined) {
254 keys = keys.filter(function (key) {
255 var exposeMetadata = index_1.defaultMetadataStorage.findExposeMetadata(target, key);
256 if (!exposeMetadata || !exposeMetadata.options)
257 return true;
258 return _this.checkVersion(exposeMetadata.options.since, exposeMetadata.options.until);
259 });
260 }
261 // apply grouping options
262 if (this.options.groups && this.options.groups.length) {
263 keys = keys.filter(function (key) {
264 var exposeMetadata = index_1.defaultMetadataStorage.findExposeMetadata(target, key);
265 if (!exposeMetadata || !exposeMetadata.options)
266 return true;
267 return _this.checkGroups(exposeMetadata.options.groups);
268 });
269 }
270 else {
271 keys = keys.filter(function (key) {
272 var exposeMetadata = index_1.defaultMetadataStorage.findExposeMetadata(target, key);
273 return !exposeMetadata ||
274 !exposeMetadata.options ||
275 !exposeMetadata.options.groups ||
276 !exposeMetadata.options.groups.length;
277 });
278 }
279 }
280 // exclude prefixed properties
281 if (this.options.excludePrefixes && this.options.excludePrefixes.length) {
282 keys = keys.filter(function (key) { return _this.options.excludePrefixes.every(function (prefix) {
283 return key.substr(0, prefix.length) !== prefix;
284 }); });
285 }
286 // make sure we have unique keys
287 keys = keys.filter(function (key, index, self) {
288 return self.indexOf(key) === index;
289 });
290 return keys;
291 };
292 TransformOperationExecutor.prototype.checkVersion = function (since, until) {
293 var decision = true;
294 if (decision && since)
295 decision = this.options.version >= since;
296 if (decision && until)
297 decision = this.options.version < until;
298 return decision;
299 };
300 TransformOperationExecutor.prototype.checkGroups = function (groups) {
301 if (!groups)
302 return true;
303 return this.options.groups.some(function (optionGroup) { return groups.indexOf(optionGroup) !== -1; });
304 };
305 return TransformOperationExecutor;
306}());
307exports.TransformOperationExecutor = TransformOperationExecutor;
308
309//# sourceMappingURL=TransformOperationExecutor.js.map