class-transformer.umd.js 54 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056
  1. (function (global, factory) {
  2. typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
  3. typeof define === 'function' && define.amd ? define(['exports'], factory) :
  4. (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.ClassTransformer = {}));
  5. })(this, (function (exports) { 'use strict';
  6. exports.TransformationType = void 0;
  7. (function (TransformationType) {
  8. TransformationType[TransformationType["PLAIN_TO_CLASS"] = 0] = "PLAIN_TO_CLASS";
  9. TransformationType[TransformationType["CLASS_TO_PLAIN"] = 1] = "CLASS_TO_PLAIN";
  10. TransformationType[TransformationType["CLASS_TO_CLASS"] = 2] = "CLASS_TO_CLASS";
  11. })(exports.TransformationType || (exports.TransformationType = {}));
  12. /**
  13. * Storage all library metadata.
  14. */
  15. var MetadataStorage = /** @class */ (function () {
  16. function MetadataStorage() {
  17. // -------------------------------------------------------------------------
  18. // Properties
  19. // -------------------------------------------------------------------------
  20. this._typeMetadatas = new Map();
  21. this._transformMetadatas = new Map();
  22. this._exposeMetadatas = new Map();
  23. this._excludeMetadatas = new Map();
  24. this._ancestorsMap = new Map();
  25. }
  26. // -------------------------------------------------------------------------
  27. // Adder Methods
  28. // -------------------------------------------------------------------------
  29. MetadataStorage.prototype.addTypeMetadata = function (metadata) {
  30. if (!this._typeMetadatas.has(metadata.target)) {
  31. this._typeMetadatas.set(metadata.target, new Map());
  32. }
  33. this._typeMetadatas.get(metadata.target).set(metadata.propertyName, metadata);
  34. };
  35. MetadataStorage.prototype.addTransformMetadata = function (metadata) {
  36. if (!this._transformMetadatas.has(metadata.target)) {
  37. this._transformMetadatas.set(metadata.target, new Map());
  38. }
  39. if (!this._transformMetadatas.get(metadata.target).has(metadata.propertyName)) {
  40. this._transformMetadatas.get(metadata.target).set(metadata.propertyName, []);
  41. }
  42. this._transformMetadatas.get(metadata.target).get(metadata.propertyName).push(metadata);
  43. };
  44. MetadataStorage.prototype.addExposeMetadata = function (metadata) {
  45. if (!this._exposeMetadatas.has(metadata.target)) {
  46. this._exposeMetadatas.set(metadata.target, new Map());
  47. }
  48. this._exposeMetadatas.get(metadata.target).set(metadata.propertyName, metadata);
  49. };
  50. MetadataStorage.prototype.addExcludeMetadata = function (metadata) {
  51. if (!this._excludeMetadatas.has(metadata.target)) {
  52. this._excludeMetadatas.set(metadata.target, new Map());
  53. }
  54. this._excludeMetadatas.get(metadata.target).set(metadata.propertyName, metadata);
  55. };
  56. // -------------------------------------------------------------------------
  57. // Public Methods
  58. // -------------------------------------------------------------------------
  59. MetadataStorage.prototype.findTransformMetadatas = function (target, propertyName, transformationType) {
  60. return this.findMetadatas(this._transformMetadatas, target, propertyName).filter(function (metadata) {
  61. if (!metadata.options)
  62. return true;
  63. if (metadata.options.toClassOnly === true && metadata.options.toPlainOnly === true)
  64. return true;
  65. if (metadata.options.toClassOnly === true) {
  66. return (transformationType === exports.TransformationType.CLASS_TO_CLASS ||
  67. transformationType === exports.TransformationType.PLAIN_TO_CLASS);
  68. }
  69. if (metadata.options.toPlainOnly === true) {
  70. return transformationType === exports.TransformationType.CLASS_TO_PLAIN;
  71. }
  72. return true;
  73. });
  74. };
  75. MetadataStorage.prototype.findExcludeMetadata = function (target, propertyName) {
  76. return this.findMetadata(this._excludeMetadatas, target, propertyName);
  77. };
  78. MetadataStorage.prototype.findExposeMetadata = function (target, propertyName) {
  79. return this.findMetadata(this._exposeMetadatas, target, propertyName);
  80. };
  81. MetadataStorage.prototype.findExposeMetadataByCustomName = function (target, name) {
  82. return this.getExposedMetadatas(target).find(function (metadata) {
  83. return metadata.options && metadata.options.name === name;
  84. });
  85. };
  86. MetadataStorage.prototype.findTypeMetadata = function (target, propertyName) {
  87. return this.findMetadata(this._typeMetadatas, target, propertyName);
  88. };
  89. MetadataStorage.prototype.getStrategy = function (target) {
  90. var excludeMap = this._excludeMetadatas.get(target);
  91. var exclude = excludeMap && excludeMap.get(undefined);
  92. var exposeMap = this._exposeMetadatas.get(target);
  93. var expose = exposeMap && exposeMap.get(undefined);
  94. if ((exclude && expose) || (!exclude && !expose))
  95. return 'none';
  96. return exclude ? 'excludeAll' : 'exposeAll';
  97. };
  98. MetadataStorage.prototype.getExposedMetadatas = function (target) {
  99. return this.getMetadata(this._exposeMetadatas, target);
  100. };
  101. MetadataStorage.prototype.getExcludedMetadatas = function (target) {
  102. return this.getMetadata(this._excludeMetadatas, target);
  103. };
  104. MetadataStorage.prototype.getExposedProperties = function (target, transformationType) {
  105. return this.getExposedMetadatas(target)
  106. .filter(function (metadata) {
  107. if (!metadata.options)
  108. return true;
  109. if (metadata.options.toClassOnly === true && metadata.options.toPlainOnly === true)
  110. return true;
  111. if (metadata.options.toClassOnly === true) {
  112. return (transformationType === exports.TransformationType.CLASS_TO_CLASS ||
  113. transformationType === exports.TransformationType.PLAIN_TO_CLASS);
  114. }
  115. if (metadata.options.toPlainOnly === true) {
  116. return transformationType === exports.TransformationType.CLASS_TO_PLAIN;
  117. }
  118. return true;
  119. })
  120. .map(function (metadata) { return metadata.propertyName; });
  121. };
  122. MetadataStorage.prototype.getExcludedProperties = function (target, transformationType) {
  123. return this.getExcludedMetadatas(target)
  124. .filter(function (metadata) {
  125. if (!metadata.options)
  126. return true;
  127. if (metadata.options.toClassOnly === true && metadata.options.toPlainOnly === true)
  128. return true;
  129. if (metadata.options.toClassOnly === true) {
  130. return (transformationType === exports.TransformationType.CLASS_TO_CLASS ||
  131. transformationType === exports.TransformationType.PLAIN_TO_CLASS);
  132. }
  133. if (metadata.options.toPlainOnly === true) {
  134. return transformationType === exports.TransformationType.CLASS_TO_PLAIN;
  135. }
  136. return true;
  137. })
  138. .map(function (metadata) { return metadata.propertyName; });
  139. };
  140. MetadataStorage.prototype.clear = function () {
  141. this._typeMetadatas.clear();
  142. this._exposeMetadatas.clear();
  143. this._excludeMetadatas.clear();
  144. this._ancestorsMap.clear();
  145. };
  146. // -------------------------------------------------------------------------
  147. // Private Methods
  148. // -------------------------------------------------------------------------
  149. MetadataStorage.prototype.getMetadata = function (metadatas, target) {
  150. var metadataFromTargetMap = metadatas.get(target);
  151. var metadataFromTarget;
  152. if (metadataFromTargetMap) {
  153. metadataFromTarget = Array.from(metadataFromTargetMap.values()).filter(function (meta) { return meta.propertyName !== undefined; });
  154. }
  155. var metadataFromAncestors = [];
  156. for (var _i = 0, _a = this.getAncestors(target); _i < _a.length; _i++) {
  157. var ancestor = _a[_i];
  158. var ancestorMetadataMap = metadatas.get(ancestor);
  159. if (ancestorMetadataMap) {
  160. var metadataFromAncestor = Array.from(ancestorMetadataMap.values()).filter(function (meta) { return meta.propertyName !== undefined; });
  161. metadataFromAncestors.push.apply(metadataFromAncestors, metadataFromAncestor);
  162. }
  163. }
  164. return metadataFromAncestors.concat(metadataFromTarget || []);
  165. };
  166. MetadataStorage.prototype.findMetadata = function (metadatas, target, propertyName) {
  167. var metadataFromTargetMap = metadatas.get(target);
  168. if (metadataFromTargetMap) {
  169. var metadataFromTarget = metadataFromTargetMap.get(propertyName);
  170. if (metadataFromTarget) {
  171. return metadataFromTarget;
  172. }
  173. }
  174. for (var _i = 0, _a = this.getAncestors(target); _i < _a.length; _i++) {
  175. var ancestor = _a[_i];
  176. var ancestorMetadataMap = metadatas.get(ancestor);
  177. if (ancestorMetadataMap) {
  178. var ancestorResult = ancestorMetadataMap.get(propertyName);
  179. if (ancestorResult) {
  180. return ancestorResult;
  181. }
  182. }
  183. }
  184. return undefined;
  185. };
  186. MetadataStorage.prototype.findMetadatas = function (metadatas, target, propertyName) {
  187. var metadataFromTargetMap = metadatas.get(target);
  188. var metadataFromTarget;
  189. if (metadataFromTargetMap) {
  190. metadataFromTarget = metadataFromTargetMap.get(propertyName);
  191. }
  192. var metadataFromAncestorsTarget = [];
  193. for (var _i = 0, _a = this.getAncestors(target); _i < _a.length; _i++) {
  194. var ancestor = _a[_i];
  195. var ancestorMetadataMap = metadatas.get(ancestor);
  196. if (ancestorMetadataMap) {
  197. if (ancestorMetadataMap.has(propertyName)) {
  198. metadataFromAncestorsTarget.push.apply(metadataFromAncestorsTarget, ancestorMetadataMap.get(propertyName));
  199. }
  200. }
  201. }
  202. return metadataFromAncestorsTarget
  203. .slice()
  204. .reverse()
  205. .concat((metadataFromTarget || []).slice().reverse());
  206. };
  207. MetadataStorage.prototype.getAncestors = function (target) {
  208. if (!target)
  209. return [];
  210. if (!this._ancestorsMap.has(target)) {
  211. var ancestors = [];
  212. for (var baseClass = Object.getPrototypeOf(target.prototype.constructor); typeof baseClass.prototype !== 'undefined'; baseClass = Object.getPrototypeOf(baseClass.prototype.constructor)) {
  213. ancestors.push(baseClass);
  214. }
  215. this._ancestorsMap.set(target, ancestors);
  216. }
  217. return this._ancestorsMap.get(target);
  218. };
  219. return MetadataStorage;
  220. }());
  221. /**
  222. * Default metadata storage is used as singleton and can be used to storage all metadatas.
  223. */
  224. var defaultMetadataStorage = new MetadataStorage();
  225. /**
  226. * This function returns the global object across Node and browsers.
  227. *
  228. * Note: `globalThis` is the standardized approach however it has been added to
  229. * Node.js in version 12. We need to include this snippet until Node 12 EOL.
  230. */
  231. function getGlobal() {
  232. if (typeof globalThis !== 'undefined') {
  233. return globalThis;
  234. }
  235. if (typeof global !== 'undefined') {
  236. return global;
  237. }
  238. // eslint-disable-next-line @typescript-eslint/ban-ts-comment
  239. // @ts-ignore: Cannot find name 'window'.
  240. if (typeof window !== 'undefined') {
  241. // eslint-disable-next-line @typescript-eslint/ban-ts-comment
  242. // @ts-ignore: Cannot find name 'window'.
  243. return window;
  244. }
  245. // eslint-disable-next-line @typescript-eslint/ban-ts-comment
  246. // @ts-ignore: Cannot find name 'self'.
  247. if (typeof self !== 'undefined') {
  248. // eslint-disable-next-line @typescript-eslint/ban-ts-comment
  249. // @ts-ignore: Cannot find name 'self'.
  250. return self;
  251. }
  252. }
  253. function isPromise(p) {
  254. return p !== null && typeof p === 'object' && typeof p.then === 'function';
  255. }
  256. var __spreadArray = (undefined && undefined.__spreadArray) || function (to, from, pack) {
  257. if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
  258. if (ar || !(i in from)) {
  259. if (!ar) ar = Array.prototype.slice.call(from, 0, i);
  260. ar[i] = from[i];
  261. }
  262. }
  263. return to.concat(ar || Array.prototype.slice.call(from));
  264. };
  265. function instantiateArrayType(arrayType) {
  266. var array = new arrayType();
  267. if (!(array instanceof Set) && !('push' in array)) {
  268. return [];
  269. }
  270. return array;
  271. }
  272. var TransformOperationExecutor = /** @class */ (function () {
  273. // -------------------------------------------------------------------------
  274. // Constructor
  275. // -------------------------------------------------------------------------
  276. function TransformOperationExecutor(transformationType, options) {
  277. this.transformationType = transformationType;
  278. this.options = options;
  279. // -------------------------------------------------------------------------
  280. // Private Properties
  281. // -------------------------------------------------------------------------
  282. this.recursionStack = new Set();
  283. }
  284. // -------------------------------------------------------------------------
  285. // Public Methods
  286. // -------------------------------------------------------------------------
  287. TransformOperationExecutor.prototype.transform = function (source, value, targetType, arrayType, isMap, level) {
  288. var _this = this;
  289. if (level === void 0) { level = 0; }
  290. if (Array.isArray(value) || value instanceof Set) {
  291. var newValue_1 = arrayType && this.transformationType === exports.TransformationType.PLAIN_TO_CLASS
  292. ? instantiateArrayType(arrayType)
  293. : [];
  294. value.forEach(function (subValue, index) {
  295. var subSource = source ? source[index] : undefined;
  296. if (!_this.options.enableCircularCheck || !_this.isCircular(subValue)) {
  297. var realTargetType = void 0;
  298. if (typeof targetType !== 'function' &&
  299. targetType &&
  300. targetType.options &&
  301. targetType.options.discriminator &&
  302. targetType.options.discriminator.property &&
  303. targetType.options.discriminator.subTypes) {
  304. if (_this.transformationType === exports.TransformationType.PLAIN_TO_CLASS) {
  305. realTargetType = targetType.options.discriminator.subTypes.find(function (subType) {
  306. return subType.name === subValue[targetType.options.discriminator.property];
  307. });
  308. var options = { newObject: newValue_1, object: subValue, property: undefined };
  309. var newType = targetType.typeFunction(options);
  310. realTargetType === undefined ? (realTargetType = newType) : (realTargetType = realTargetType.value);
  311. if (!targetType.options.keepDiscriminatorProperty)
  312. delete subValue[targetType.options.discriminator.property];
  313. }
  314. if (_this.transformationType === exports.TransformationType.CLASS_TO_CLASS) {
  315. realTargetType = subValue.constructor;
  316. }
  317. if (_this.transformationType === exports.TransformationType.CLASS_TO_PLAIN) {
  318. subValue[targetType.options.discriminator.property] = targetType.options.discriminator.subTypes.find(function (subType) { return subType.value === subValue.constructor; }).name;
  319. }
  320. }
  321. else {
  322. realTargetType = targetType;
  323. }
  324. var value_1 = _this.transform(subSource, subValue, realTargetType, undefined, subValue instanceof Map, level + 1);
  325. if (newValue_1 instanceof Set) {
  326. newValue_1.add(value_1);
  327. }
  328. else {
  329. newValue_1.push(value_1);
  330. }
  331. }
  332. else if (_this.transformationType === exports.TransformationType.CLASS_TO_CLASS) {
  333. if (newValue_1 instanceof Set) {
  334. newValue_1.add(subValue);
  335. }
  336. else {
  337. newValue_1.push(subValue);
  338. }
  339. }
  340. });
  341. return newValue_1;
  342. }
  343. else if (targetType === String && !isMap) {
  344. if (value === null || value === undefined)
  345. return value;
  346. return String(value);
  347. }
  348. else if (targetType === Number && !isMap) {
  349. if (value === null || value === undefined)
  350. return value;
  351. return Number(value);
  352. }
  353. else if (targetType === Boolean && !isMap) {
  354. if (value === null || value === undefined)
  355. return value;
  356. return Boolean(value);
  357. }
  358. else if ((targetType === Date || value instanceof Date) && !isMap) {
  359. if (value instanceof Date) {
  360. return new Date(value.valueOf());
  361. }
  362. if (value === null || value === undefined)
  363. return value;
  364. return new Date(value);
  365. }
  366. else if (!!getGlobal().Buffer && (targetType === Buffer || value instanceof Buffer) && !isMap) {
  367. if (value === null || value === undefined)
  368. return value;
  369. return Buffer.from(value);
  370. }
  371. else if (isPromise(value) && !isMap) {
  372. return new Promise(function (resolve, reject) {
  373. value.then(function (data) { return resolve(_this.transform(undefined, data, targetType, undefined, undefined, level + 1)); }, reject);
  374. });
  375. }
  376. else if (!isMap && value !== null && typeof value === 'object' && typeof value.then === 'function') {
  377. // Note: We should not enter this, as promise has been handled above
  378. // This option simply returns the Promise preventing a JS error from happening and should be an inaccessible path.
  379. return value; // skip promise transformation
  380. }
  381. else if (typeof value === 'object' && value !== null) {
  382. // try to guess the type
  383. if (!targetType && value.constructor !== Object /* && TransformationType === TransformationType.CLASS_TO_PLAIN*/)
  384. if (!Array.isArray(value) && value.constructor === Array) ;
  385. else {
  386. // We are good we can use the built-in constructor
  387. targetType = value.constructor;
  388. }
  389. if (!targetType && source)
  390. targetType = source.constructor;
  391. if (this.options.enableCircularCheck) {
  392. // add transformed type to prevent circular references
  393. this.recursionStack.add(value);
  394. }
  395. var keys = this.getKeys(targetType, value, isMap);
  396. var newValue = source ? source : {};
  397. if (!source &&
  398. (this.transformationType === exports.TransformationType.PLAIN_TO_CLASS ||
  399. this.transformationType === exports.TransformationType.CLASS_TO_CLASS)) {
  400. if (isMap) {
  401. newValue = new Map();
  402. }
  403. else if (targetType) {
  404. newValue = new targetType();
  405. }
  406. else {
  407. newValue = {};
  408. }
  409. }
  410. var _loop_1 = function (key) {
  411. if (key === '__proto__' || key === 'constructor') {
  412. return "continue";
  413. }
  414. var valueKey = key;
  415. var newValueKey = key, propertyName = key;
  416. if (!this_1.options.ignoreDecorators && targetType) {
  417. if (this_1.transformationType === exports.TransformationType.PLAIN_TO_CLASS) {
  418. var exposeMetadata = defaultMetadataStorage.findExposeMetadataByCustomName(targetType, key);
  419. if (exposeMetadata) {
  420. propertyName = exposeMetadata.propertyName;
  421. newValueKey = exposeMetadata.propertyName;
  422. }
  423. }
  424. else if (this_1.transformationType === exports.TransformationType.CLASS_TO_PLAIN ||
  425. this_1.transformationType === exports.TransformationType.CLASS_TO_CLASS) {
  426. var exposeMetadata = defaultMetadataStorage.findExposeMetadata(targetType, key);
  427. if (exposeMetadata && exposeMetadata.options && exposeMetadata.options.name) {
  428. newValueKey = exposeMetadata.options.name;
  429. }
  430. }
  431. }
  432. // get a subvalue
  433. var subValue = undefined;
  434. if (this_1.transformationType === exports.TransformationType.PLAIN_TO_CLASS) {
  435. /**
  436. * This section is added for the following report:
  437. * https://github.com/typestack/class-transformer/issues/596
  438. *
  439. * We should not call functions or constructors when transforming to class.
  440. */
  441. subValue = value[valueKey];
  442. }
  443. else {
  444. if (value instanceof Map) {
  445. subValue = value.get(valueKey);
  446. }
  447. else if (value[valueKey] instanceof Function) {
  448. subValue = value[valueKey]();
  449. }
  450. else {
  451. subValue = value[valueKey];
  452. }
  453. }
  454. // determine a type
  455. var type = undefined, isSubValueMap = subValue instanceof Map;
  456. if (targetType && isMap) {
  457. type = targetType;
  458. }
  459. else if (targetType) {
  460. var metadata_1 = defaultMetadataStorage.findTypeMetadata(targetType, propertyName);
  461. if (metadata_1) {
  462. var options = { newObject: newValue, object: value, property: propertyName };
  463. var newType = metadata_1.typeFunction ? metadata_1.typeFunction(options) : metadata_1.reflectedType;
  464. if (metadata_1.options &&
  465. metadata_1.options.discriminator &&
  466. metadata_1.options.discriminator.property &&
  467. metadata_1.options.discriminator.subTypes) {
  468. if (!(value[valueKey] instanceof Array)) {
  469. if (this_1.transformationType === exports.TransformationType.PLAIN_TO_CLASS) {
  470. type = metadata_1.options.discriminator.subTypes.find(function (subType) {
  471. if (subValue && subValue instanceof Object && metadata_1.options.discriminator.property in subValue) {
  472. return subType.name === subValue[metadata_1.options.discriminator.property];
  473. }
  474. });
  475. type === undefined ? (type = newType) : (type = type.value);
  476. if (!metadata_1.options.keepDiscriminatorProperty) {
  477. if (subValue && subValue instanceof Object && metadata_1.options.discriminator.property in subValue) {
  478. delete subValue[metadata_1.options.discriminator.property];
  479. }
  480. }
  481. }
  482. if (this_1.transformationType === exports.TransformationType.CLASS_TO_CLASS) {
  483. type = subValue.constructor;
  484. }
  485. if (this_1.transformationType === exports.TransformationType.CLASS_TO_PLAIN) {
  486. if (subValue) {
  487. subValue[metadata_1.options.discriminator.property] = metadata_1.options.discriminator.subTypes.find(function (subType) { return subType.value === subValue.constructor; }).name;
  488. }
  489. }
  490. }
  491. else {
  492. type = metadata_1;
  493. }
  494. }
  495. else {
  496. type = newType;
  497. }
  498. isSubValueMap = isSubValueMap || metadata_1.reflectedType === Map;
  499. }
  500. else if (this_1.options.targetMaps) {
  501. // try to find a type in target maps
  502. this_1.options.targetMaps
  503. .filter(function (map) { return map.target === targetType && !!map.properties[propertyName]; })
  504. .forEach(function (map) { return (type = map.properties[propertyName]); });
  505. }
  506. else if (this_1.options.enableImplicitConversion &&
  507. this_1.transformationType === exports.TransformationType.PLAIN_TO_CLASS) {
  508. // if we have no registererd type via the @Type() decorator then we check if we have any
  509. // type declarations in reflect-metadata (type declaration is emited only if some decorator is added to the property.)
  510. var reflectedType = Reflect.getMetadata('design:type', targetType.prototype, propertyName);
  511. if (reflectedType) {
  512. type = reflectedType;
  513. }
  514. }
  515. }
  516. // if value is an array try to get its custom array type
  517. var arrayType_1 = Array.isArray(value[valueKey])
  518. ? this_1.getReflectedType(targetType, propertyName)
  519. : undefined;
  520. // const subValueKey = TransformationType === TransformationType.PLAIN_TO_CLASS && newKeyName ? newKeyName : key;
  521. var subSource = source ? source[valueKey] : undefined;
  522. // if its deserialization then type if required
  523. // if we uncomment this types like string[] will not work
  524. // if (this.transformationType === TransformationType.PLAIN_TO_CLASS && !type && subValue instanceof Object && !(subValue instanceof Date))
  525. // throw new Error(`Cannot determine type for ${(targetType as any).name }.${propertyName}, did you forget to specify a @Type?`);
  526. // if newValue is a source object that has method that match newKeyName then skip it
  527. if (newValue.constructor.prototype) {
  528. var descriptor = Object.getOwnPropertyDescriptor(newValue.constructor.prototype, newValueKey);
  529. if ((this_1.transformationType === exports.TransformationType.PLAIN_TO_CLASS ||
  530. this_1.transformationType === exports.TransformationType.CLASS_TO_CLASS) &&
  531. // eslint-disable-next-line @typescript-eslint/unbound-method
  532. ((descriptor && !descriptor.set) || newValue[newValueKey] instanceof Function))
  533. return "continue";
  534. }
  535. if (!this_1.options.enableCircularCheck || !this_1.isCircular(subValue)) {
  536. var transformKey = this_1.transformationType === exports.TransformationType.PLAIN_TO_CLASS ? newValueKey : key;
  537. var finalValue = void 0;
  538. if (this_1.transformationType === exports.TransformationType.CLASS_TO_PLAIN) {
  539. // Get original value
  540. finalValue = value[transformKey];
  541. // Apply custom transformation
  542. finalValue = this_1.applyCustomTransformations(finalValue, targetType, transformKey, value, this_1.transformationType);
  543. // If nothing change, it means no custom transformation was applied, so use the subValue.
  544. finalValue = value[transformKey] === finalValue ? subValue : finalValue;
  545. // Apply the default transformation
  546. finalValue = this_1.transform(subSource, finalValue, type, arrayType_1, isSubValueMap, level + 1);
  547. }
  548. else {
  549. if (subValue === undefined && this_1.options.exposeDefaultValues) {
  550. // Set default value if nothing provided
  551. finalValue = newValue[newValueKey];
  552. }
  553. else {
  554. finalValue = this_1.transform(subSource, subValue, type, arrayType_1, isSubValueMap, level + 1);
  555. finalValue = this_1.applyCustomTransformations(finalValue, targetType, transformKey, value, this_1.transformationType);
  556. }
  557. }
  558. if (finalValue !== undefined || this_1.options.exposeUnsetFields) {
  559. if (newValue instanceof Map) {
  560. newValue.set(newValueKey, finalValue);
  561. }
  562. else {
  563. newValue[newValueKey] = finalValue;
  564. }
  565. }
  566. }
  567. else if (this_1.transformationType === exports.TransformationType.CLASS_TO_CLASS) {
  568. var finalValue = subValue;
  569. finalValue = this_1.applyCustomTransformations(finalValue, targetType, key, value, this_1.transformationType);
  570. if (finalValue !== undefined || this_1.options.exposeUnsetFields) {
  571. if (newValue instanceof Map) {
  572. newValue.set(newValueKey, finalValue);
  573. }
  574. else {
  575. newValue[newValueKey] = finalValue;
  576. }
  577. }
  578. }
  579. };
  580. var this_1 = this;
  581. // traverse over keys
  582. for (var _i = 0, keys_1 = keys; _i < keys_1.length; _i++) {
  583. var key = keys_1[_i];
  584. _loop_1(key);
  585. }
  586. if (this.options.enableCircularCheck) {
  587. this.recursionStack.delete(value);
  588. }
  589. return newValue;
  590. }
  591. else {
  592. return value;
  593. }
  594. };
  595. TransformOperationExecutor.prototype.applyCustomTransformations = function (value, target, key, obj, transformationType) {
  596. var _this = this;
  597. var metadatas = defaultMetadataStorage.findTransformMetadatas(target, key, this.transformationType);
  598. // apply versioning options
  599. if (this.options.version !== undefined) {
  600. metadatas = metadatas.filter(function (metadata) {
  601. if (!metadata.options)
  602. return true;
  603. return _this.checkVersion(metadata.options.since, metadata.options.until);
  604. });
  605. }
  606. // apply grouping options
  607. if (this.options.groups && this.options.groups.length) {
  608. metadatas = metadatas.filter(function (metadata) {
  609. if (!metadata.options)
  610. return true;
  611. return _this.checkGroups(metadata.options.groups);
  612. });
  613. }
  614. else {
  615. metadatas = metadatas.filter(function (metadata) {
  616. return !metadata.options || !metadata.options.groups || !metadata.options.groups.length;
  617. });
  618. }
  619. metadatas.forEach(function (metadata) {
  620. value = metadata.transformFn({ value: value, key: key, obj: obj, type: transformationType, options: _this.options });
  621. });
  622. return value;
  623. };
  624. // preventing circular references
  625. TransformOperationExecutor.prototype.isCircular = function (object) {
  626. return this.recursionStack.has(object);
  627. };
  628. TransformOperationExecutor.prototype.getReflectedType = function (target, propertyName) {
  629. if (!target)
  630. return undefined;
  631. var meta = defaultMetadataStorage.findTypeMetadata(target, propertyName);
  632. return meta ? meta.reflectedType : undefined;
  633. };
  634. TransformOperationExecutor.prototype.getKeys = function (target, object, isMap) {
  635. var _this = this;
  636. // determine exclusion strategy
  637. var strategy = defaultMetadataStorage.getStrategy(target);
  638. if (strategy === 'none')
  639. strategy = this.options.strategy || 'exposeAll'; // exposeAll is default strategy
  640. // get all keys that need to expose
  641. var keys = [];
  642. if (strategy === 'exposeAll' || isMap) {
  643. if (object instanceof Map) {
  644. keys = Array.from(object.keys());
  645. }
  646. else {
  647. keys = Object.keys(object);
  648. }
  649. }
  650. if (isMap) {
  651. // expose & exclude do not apply for map keys only to fields
  652. return keys;
  653. }
  654. /**
  655. * If decorators are ignored but we don't want the extraneous values, then we use the
  656. * metadata to decide which property is needed, but doesn't apply the decorator effect.
  657. */
  658. if (this.options.ignoreDecorators && this.options.excludeExtraneousValues && target) {
  659. var exposedProperties = defaultMetadataStorage.getExposedProperties(target, this.transformationType);
  660. var excludedProperties = defaultMetadataStorage.getExcludedProperties(target, this.transformationType);
  661. keys = __spreadArray(__spreadArray([], exposedProperties, true), excludedProperties, true);
  662. }
  663. if (!this.options.ignoreDecorators && target) {
  664. // add all exposed to list of keys
  665. var exposedProperties = defaultMetadataStorage.getExposedProperties(target, this.transformationType);
  666. if (this.transformationType === exports.TransformationType.PLAIN_TO_CLASS) {
  667. exposedProperties = exposedProperties.map(function (key) {
  668. var exposeMetadata = defaultMetadataStorage.findExposeMetadata(target, key);
  669. if (exposeMetadata && exposeMetadata.options && exposeMetadata.options.name) {
  670. return exposeMetadata.options.name;
  671. }
  672. return key;
  673. });
  674. }
  675. if (this.options.excludeExtraneousValues) {
  676. keys = exposedProperties;
  677. }
  678. else {
  679. keys = keys.concat(exposedProperties);
  680. }
  681. // exclude excluded properties
  682. var excludedProperties_1 = defaultMetadataStorage.getExcludedProperties(target, this.transformationType);
  683. if (excludedProperties_1.length > 0) {
  684. keys = keys.filter(function (key) {
  685. return !excludedProperties_1.includes(key);
  686. });
  687. }
  688. // apply versioning options
  689. if (this.options.version !== undefined) {
  690. keys = keys.filter(function (key) {
  691. var exposeMetadata = defaultMetadataStorage.findExposeMetadata(target, key);
  692. if (!exposeMetadata || !exposeMetadata.options)
  693. return true;
  694. return _this.checkVersion(exposeMetadata.options.since, exposeMetadata.options.until);
  695. });
  696. }
  697. // apply grouping options
  698. if (this.options.groups && this.options.groups.length) {
  699. keys = keys.filter(function (key) {
  700. var exposeMetadata = defaultMetadataStorage.findExposeMetadata(target, key);
  701. if (!exposeMetadata || !exposeMetadata.options)
  702. return true;
  703. return _this.checkGroups(exposeMetadata.options.groups);
  704. });
  705. }
  706. else {
  707. keys = keys.filter(function (key) {
  708. var exposeMetadata = defaultMetadataStorage.findExposeMetadata(target, key);
  709. return (!exposeMetadata ||
  710. !exposeMetadata.options ||
  711. !exposeMetadata.options.groups ||
  712. !exposeMetadata.options.groups.length);
  713. });
  714. }
  715. }
  716. // exclude prefixed properties
  717. if (this.options.excludePrefixes && this.options.excludePrefixes.length) {
  718. keys = keys.filter(function (key) {
  719. return _this.options.excludePrefixes.every(function (prefix) {
  720. return key.substr(0, prefix.length) !== prefix;
  721. });
  722. });
  723. }
  724. // make sure we have unique keys
  725. keys = keys.filter(function (key, index, self) {
  726. return self.indexOf(key) === index;
  727. });
  728. return keys;
  729. };
  730. TransformOperationExecutor.prototype.checkVersion = function (since, until) {
  731. var decision = true;
  732. if (decision && since)
  733. decision = this.options.version >= since;
  734. if (decision && until)
  735. decision = this.options.version < until;
  736. return decision;
  737. };
  738. TransformOperationExecutor.prototype.checkGroups = function (groups) {
  739. if (!groups)
  740. return true;
  741. return this.options.groups.some(function (optionGroup) { return groups.includes(optionGroup); });
  742. };
  743. return TransformOperationExecutor;
  744. }());
  745. /**
  746. * These are the default options used by any transformation operation.
  747. */
  748. var defaultOptions = {
  749. enableCircularCheck: false,
  750. enableImplicitConversion: false,
  751. excludeExtraneousValues: false,
  752. excludePrefixes: undefined,
  753. exposeDefaultValues: false,
  754. exposeUnsetFields: true,
  755. groups: undefined,
  756. ignoreDecorators: false,
  757. strategy: undefined,
  758. targetMaps: undefined,
  759. version: undefined,
  760. };
  761. var __assign = (undefined && undefined.__assign) || function () {
  762. __assign = Object.assign || function(t) {
  763. for (var s, i = 1, n = arguments.length; i < n; i++) {
  764. s = arguments[i];
  765. for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
  766. t[p] = s[p];
  767. }
  768. return t;
  769. };
  770. return __assign.apply(this, arguments);
  771. };
  772. var ClassTransformer = /** @class */ (function () {
  773. function ClassTransformer() {
  774. }
  775. ClassTransformer.prototype.instanceToPlain = function (object, options) {
  776. var executor = new TransformOperationExecutor(exports.TransformationType.CLASS_TO_PLAIN, __assign(__assign({}, defaultOptions), options));
  777. return executor.transform(undefined, object, undefined, undefined, undefined, undefined);
  778. };
  779. ClassTransformer.prototype.classToPlainFromExist = function (object, plainObject, options) {
  780. var executor = new TransformOperationExecutor(exports.TransformationType.CLASS_TO_PLAIN, __assign(__assign({}, defaultOptions), options));
  781. return executor.transform(plainObject, object, undefined, undefined, undefined, undefined);
  782. };
  783. ClassTransformer.prototype.plainToInstance = function (cls, plain, options) {
  784. var executor = new TransformOperationExecutor(exports.TransformationType.PLAIN_TO_CLASS, __assign(__assign({}, defaultOptions), options));
  785. return executor.transform(undefined, plain, cls, undefined, undefined, undefined);
  786. };
  787. ClassTransformer.prototype.plainToClassFromExist = function (clsObject, plain, options) {
  788. var executor = new TransformOperationExecutor(exports.TransformationType.PLAIN_TO_CLASS, __assign(__assign({}, defaultOptions), options));
  789. return executor.transform(clsObject, plain, undefined, undefined, undefined, undefined);
  790. };
  791. ClassTransformer.prototype.instanceToInstance = function (object, options) {
  792. var executor = new TransformOperationExecutor(exports.TransformationType.CLASS_TO_CLASS, __assign(__assign({}, defaultOptions), options));
  793. return executor.transform(undefined, object, undefined, undefined, undefined, undefined);
  794. };
  795. ClassTransformer.prototype.classToClassFromExist = function (object, fromObject, options) {
  796. var executor = new TransformOperationExecutor(exports.TransformationType.CLASS_TO_CLASS, __assign(__assign({}, defaultOptions), options));
  797. return executor.transform(fromObject, object, undefined, undefined, undefined, undefined);
  798. };
  799. ClassTransformer.prototype.serialize = function (object, options) {
  800. return JSON.stringify(this.instanceToPlain(object, options));
  801. };
  802. /**
  803. * Deserializes given JSON string to a object of the given class.
  804. */
  805. ClassTransformer.prototype.deserialize = function (cls, json, options) {
  806. var jsonObject = JSON.parse(json);
  807. return this.plainToInstance(cls, jsonObject, options);
  808. };
  809. /**
  810. * Deserializes given JSON string to an array of objects of the given class.
  811. */
  812. ClassTransformer.prototype.deserializeArray = function (cls, json, options) {
  813. var jsonObject = JSON.parse(json);
  814. return this.plainToInstance(cls, jsonObject, options);
  815. };
  816. return ClassTransformer;
  817. }());
  818. /**
  819. * Marks the given class or property as excluded. By default the property is excluded in both
  820. * constructorToPlain and plainToConstructor transformations. It can be limited to only one direction
  821. * via using the `toPlainOnly` or `toClassOnly` option.
  822. *
  823. * Can be applied to class definitions and properties.
  824. */
  825. function Exclude(options) {
  826. if (options === void 0) { options = {}; }
  827. /**
  828. * NOTE: The `propertyName` property must be marked as optional because
  829. * this decorator used both as a class and a property decorator and the
  830. * Typescript compiler will freak out if we make it mandatory as a class
  831. * decorator only receives one parameter.
  832. */
  833. return function (object, propertyName) {
  834. defaultMetadataStorage.addExcludeMetadata({
  835. target: object instanceof Function ? object : object.constructor,
  836. propertyName: propertyName,
  837. options: options,
  838. });
  839. };
  840. }
  841. /**
  842. * Marks the given class or property as included. By default the property is included in both
  843. * constructorToPlain and plainToConstructor transformations. It can be limited to only one direction
  844. * via using the `toPlainOnly` or `toClassOnly` option.
  845. *
  846. * Can be applied to class definitions and properties.
  847. */
  848. function Expose(options) {
  849. if (options === void 0) { options = {}; }
  850. /**
  851. * NOTE: The `propertyName` property must be marked as optional because
  852. * this decorator used both as a class and a property decorator and the
  853. * Typescript compiler will freak out if we make it mandatory as a class
  854. * decorator only receives one parameter.
  855. */
  856. return function (object, propertyName) {
  857. defaultMetadataStorage.addExposeMetadata({
  858. target: object instanceof Function ? object : object.constructor,
  859. propertyName: propertyName,
  860. options: options,
  861. });
  862. };
  863. }
  864. /**
  865. * Return the class instance only with the exposed properties.
  866. *
  867. * Can be applied to functions and getters/setters only.
  868. */
  869. function TransformInstanceToInstance(params) {
  870. return function (target, propertyKey, descriptor) {
  871. var classTransformer = new ClassTransformer();
  872. var originalMethod = descriptor.value;
  873. descriptor.value = function () {
  874. var args = [];
  875. for (var _i = 0; _i < arguments.length; _i++) {
  876. args[_i] = arguments[_i];
  877. }
  878. var result = originalMethod.apply(this, args);
  879. var isPromise = !!result && (typeof result === 'object' || typeof result === 'function') && typeof result.then === 'function';
  880. return isPromise
  881. ? result.then(function (data) { return classTransformer.instanceToInstance(data, params); })
  882. : classTransformer.instanceToInstance(result, params);
  883. };
  884. };
  885. }
  886. /**
  887. * Transform the object from class to plain object and return only with the exposed properties.
  888. *
  889. * Can be applied to functions and getters/setters only.
  890. */
  891. function TransformInstanceToPlain(params) {
  892. return function (target, propertyKey, descriptor) {
  893. var classTransformer = new ClassTransformer();
  894. var originalMethod = descriptor.value;
  895. descriptor.value = function () {
  896. var args = [];
  897. for (var _i = 0; _i < arguments.length; _i++) {
  898. args[_i] = arguments[_i];
  899. }
  900. var result = originalMethod.apply(this, args);
  901. var isPromise = !!result && (typeof result === 'object' || typeof result === 'function') && typeof result.then === 'function';
  902. return isPromise
  903. ? result.then(function (data) { return classTransformer.instanceToPlain(data, params); })
  904. : classTransformer.instanceToPlain(result, params);
  905. };
  906. };
  907. }
  908. /**
  909. * Return the class instance only with the exposed properties.
  910. *
  911. * Can be applied to functions and getters/setters only.
  912. */
  913. function TransformPlainToInstance(classType, params) {
  914. return function (target, propertyKey, descriptor) {
  915. var classTransformer = new ClassTransformer();
  916. var originalMethod = descriptor.value;
  917. descriptor.value = function () {
  918. var args = [];
  919. for (var _i = 0; _i < arguments.length; _i++) {
  920. args[_i] = arguments[_i];
  921. }
  922. var result = originalMethod.apply(this, args);
  923. var isPromise = !!result && (typeof result === 'object' || typeof result === 'function') && typeof result.then === 'function';
  924. return isPromise
  925. ? result.then(function (data) { return classTransformer.plainToInstance(classType, data, params); })
  926. : classTransformer.plainToInstance(classType, result, params);
  927. };
  928. };
  929. }
  930. /**
  931. * Defines a custom logic for value transformation.
  932. *
  933. * Can be applied to properties only.
  934. */
  935. function Transform(transformFn, options) {
  936. if (options === void 0) { options = {}; }
  937. return function (target, propertyName) {
  938. defaultMetadataStorage.addTransformMetadata({
  939. target: target.constructor,
  940. propertyName: propertyName,
  941. transformFn: transformFn,
  942. options: options,
  943. });
  944. };
  945. }
  946. /**
  947. * Specifies a type of the property.
  948. * The given TypeFunction can return a constructor. A discriminator can be given in the options.
  949. *
  950. * Can be applied to properties only.
  951. */
  952. function Type(typeFunction, options) {
  953. if (options === void 0) { options = {}; }
  954. return function (target, propertyName) {
  955. var reflectedType = Reflect.getMetadata('design:type', target, propertyName);
  956. defaultMetadataStorage.addTypeMetadata({
  957. target: target.constructor,
  958. propertyName: propertyName,
  959. reflectedType: reflectedType,
  960. typeFunction: typeFunction,
  961. options: options,
  962. });
  963. };
  964. }
  965. var classTransformer = new ClassTransformer();
  966. function classToPlain(object, options) {
  967. return classTransformer.instanceToPlain(object, options);
  968. }
  969. function instanceToPlain(object, options) {
  970. return classTransformer.instanceToPlain(object, options);
  971. }
  972. function classToPlainFromExist(object, plainObject, options) {
  973. return classTransformer.classToPlainFromExist(object, plainObject, options);
  974. }
  975. function plainToClass(cls, plain, options) {
  976. return classTransformer.plainToInstance(cls, plain, options);
  977. }
  978. function plainToInstance(cls, plain, options) {
  979. return classTransformer.plainToInstance(cls, plain, options);
  980. }
  981. function plainToClassFromExist(clsObject, plain, options) {
  982. return classTransformer.plainToClassFromExist(clsObject, plain, options);
  983. }
  984. function instanceToInstance(object, options) {
  985. return classTransformer.instanceToInstance(object, options);
  986. }
  987. function classToClassFromExist(object, fromObject, options) {
  988. return classTransformer.classToClassFromExist(object, fromObject, options);
  989. }
  990. function serialize(object, options) {
  991. return classTransformer.serialize(object, options);
  992. }
  993. /**
  994. * Deserializes given JSON string to a object of the given class.
  995. *
  996. * @deprecated This function is being removed. Please use the following instead:
  997. * ```
  998. * instanceToClass(cls, JSON.parse(json), options)
  999. * ```
  1000. */
  1001. function deserialize(cls, json, options) {
  1002. return classTransformer.deserialize(cls, json, options);
  1003. }
  1004. /**
  1005. * Deserializes given JSON string to an array of objects of the given class.
  1006. *
  1007. * @deprecated This function is being removed. Please use the following instead:
  1008. * ```
  1009. * JSON.parse(json).map(value => instanceToClass(cls, value, options))
  1010. * ```
  1011. *
  1012. */
  1013. function deserializeArray(cls, json, options) {
  1014. return classTransformer.deserializeArray(cls, json, options);
  1015. }
  1016. exports.ClassTransformer = ClassTransformer;
  1017. exports.Exclude = Exclude;
  1018. exports.Expose = Expose;
  1019. exports.Transform = Transform;
  1020. exports.TransformInstanceToInstance = TransformInstanceToInstance;
  1021. exports.TransformInstanceToPlain = TransformInstanceToPlain;
  1022. exports.TransformPlainToInstance = TransformPlainToInstance;
  1023. exports.Type = Type;
  1024. exports.classToClassFromExist = classToClassFromExist;
  1025. exports.classToPlain = classToPlain;
  1026. exports.classToPlainFromExist = classToPlainFromExist;
  1027. exports.deserialize = deserialize;
  1028. exports.deserializeArray = deserializeArray;
  1029. exports.instanceToInstance = instanceToInstance;
  1030. exports.instanceToPlain = instanceToPlain;
  1031. exports.plainToClass = plainToClass;
  1032. exports.plainToClassFromExist = plainToClassFromExist;
  1033. exports.plainToInstance = plainToInstance;
  1034. exports.serialize = serialize;
  1035. Object.defineProperty(exports, '__esModule', { value: true });
  1036. }));
  1037. //# sourceMappingURL=class-transformer.umd.js.map