
- Complete NestJS TypeScript implementation with WebSocket support - Direct messaging (DM) and group chat functionality - End-to-end encryption with AES encryption and key pairs - Media file support (images, videos, audio, documents) up to 100MB - Push notifications with Firebase Cloud Messaging integration - Mention alerts and real-time typing indicators - User authentication with JWT and Passport - SQLite database with TypeORM entities and relationships - Comprehensive API documentation with Swagger/OpenAPI - File upload handling with secure access control - Online/offline status tracking and presence management - Message editing, deletion, and reply functionality - Notification management with automatic cleanup - Health check endpoint for monitoring - CORS configuration for cross-origin requests - Environment-based configuration management - Structured for Flutter SDK integration Features implemented: ✅ Real-time messaging with Socket.IO ✅ User registration and authentication ✅ Direct messages and group chats ✅ Media file uploads and management ✅ End-to-end encryption ✅ Push notifications ✅ Mention alerts ✅ Typing indicators ✅ Message read receipts ✅ Online status tracking ✅ File access control ✅ Comprehensive API documentation Ready for Flutter SDK development and production deployment.
1057 lines
54 KiB
JavaScript
1057 lines
54 KiB
JavaScript
(function (global, factory) {
|
|
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
|
|
typeof define === 'function' && define.amd ? define(['exports'], factory) :
|
|
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.ClassTransformer = {}));
|
|
})(this, (function (exports) { 'use strict';
|
|
|
|
exports.TransformationType = void 0;
|
|
(function (TransformationType) {
|
|
TransformationType[TransformationType["PLAIN_TO_CLASS"] = 0] = "PLAIN_TO_CLASS";
|
|
TransformationType[TransformationType["CLASS_TO_PLAIN"] = 1] = "CLASS_TO_PLAIN";
|
|
TransformationType[TransformationType["CLASS_TO_CLASS"] = 2] = "CLASS_TO_CLASS";
|
|
})(exports.TransformationType || (exports.TransformationType = {}));
|
|
|
|
/**
|
|
* Storage all library metadata.
|
|
*/
|
|
var MetadataStorage = /** @class */ (function () {
|
|
function MetadataStorage() {
|
|
// -------------------------------------------------------------------------
|
|
// Properties
|
|
// -------------------------------------------------------------------------
|
|
this._typeMetadatas = new Map();
|
|
this._transformMetadatas = new Map();
|
|
this._exposeMetadatas = new Map();
|
|
this._excludeMetadatas = new Map();
|
|
this._ancestorsMap = new Map();
|
|
}
|
|
// -------------------------------------------------------------------------
|
|
// Adder Methods
|
|
// -------------------------------------------------------------------------
|
|
MetadataStorage.prototype.addTypeMetadata = function (metadata) {
|
|
if (!this._typeMetadatas.has(metadata.target)) {
|
|
this._typeMetadatas.set(metadata.target, new Map());
|
|
}
|
|
this._typeMetadatas.get(metadata.target).set(metadata.propertyName, metadata);
|
|
};
|
|
MetadataStorage.prototype.addTransformMetadata = function (metadata) {
|
|
if (!this._transformMetadatas.has(metadata.target)) {
|
|
this._transformMetadatas.set(metadata.target, new Map());
|
|
}
|
|
if (!this._transformMetadatas.get(metadata.target).has(metadata.propertyName)) {
|
|
this._transformMetadatas.get(metadata.target).set(metadata.propertyName, []);
|
|
}
|
|
this._transformMetadatas.get(metadata.target).get(metadata.propertyName).push(metadata);
|
|
};
|
|
MetadataStorage.prototype.addExposeMetadata = function (metadata) {
|
|
if (!this._exposeMetadatas.has(metadata.target)) {
|
|
this._exposeMetadatas.set(metadata.target, new Map());
|
|
}
|
|
this._exposeMetadatas.get(metadata.target).set(metadata.propertyName, metadata);
|
|
};
|
|
MetadataStorage.prototype.addExcludeMetadata = function (metadata) {
|
|
if (!this._excludeMetadatas.has(metadata.target)) {
|
|
this._excludeMetadatas.set(metadata.target, new Map());
|
|
}
|
|
this._excludeMetadatas.get(metadata.target).set(metadata.propertyName, metadata);
|
|
};
|
|
// -------------------------------------------------------------------------
|
|
// Public Methods
|
|
// -------------------------------------------------------------------------
|
|
MetadataStorage.prototype.findTransformMetadatas = function (target, propertyName, transformationType) {
|
|
return this.findMetadatas(this._transformMetadatas, target, propertyName).filter(function (metadata) {
|
|
if (!metadata.options)
|
|
return true;
|
|
if (metadata.options.toClassOnly === true && metadata.options.toPlainOnly === true)
|
|
return true;
|
|
if (metadata.options.toClassOnly === true) {
|
|
return (transformationType === exports.TransformationType.CLASS_TO_CLASS ||
|
|
transformationType === exports.TransformationType.PLAIN_TO_CLASS);
|
|
}
|
|
if (metadata.options.toPlainOnly === true) {
|
|
return transformationType === exports.TransformationType.CLASS_TO_PLAIN;
|
|
}
|
|
return true;
|
|
});
|
|
};
|
|
MetadataStorage.prototype.findExcludeMetadata = function (target, propertyName) {
|
|
return this.findMetadata(this._excludeMetadatas, target, propertyName);
|
|
};
|
|
MetadataStorage.prototype.findExposeMetadata = function (target, propertyName) {
|
|
return this.findMetadata(this._exposeMetadatas, target, propertyName);
|
|
};
|
|
MetadataStorage.prototype.findExposeMetadataByCustomName = function (target, name) {
|
|
return this.getExposedMetadatas(target).find(function (metadata) {
|
|
return metadata.options && metadata.options.name === name;
|
|
});
|
|
};
|
|
MetadataStorage.prototype.findTypeMetadata = function (target, propertyName) {
|
|
return this.findMetadata(this._typeMetadatas, target, propertyName);
|
|
};
|
|
MetadataStorage.prototype.getStrategy = function (target) {
|
|
var excludeMap = this._excludeMetadatas.get(target);
|
|
var exclude = excludeMap && excludeMap.get(undefined);
|
|
var exposeMap = this._exposeMetadatas.get(target);
|
|
var expose = exposeMap && exposeMap.get(undefined);
|
|
if ((exclude && expose) || (!exclude && !expose))
|
|
return 'none';
|
|
return exclude ? 'excludeAll' : 'exposeAll';
|
|
};
|
|
MetadataStorage.prototype.getExposedMetadatas = function (target) {
|
|
return this.getMetadata(this._exposeMetadatas, target);
|
|
};
|
|
MetadataStorage.prototype.getExcludedMetadatas = function (target) {
|
|
return this.getMetadata(this._excludeMetadatas, target);
|
|
};
|
|
MetadataStorage.prototype.getExposedProperties = function (target, transformationType) {
|
|
return this.getExposedMetadatas(target)
|
|
.filter(function (metadata) {
|
|
if (!metadata.options)
|
|
return true;
|
|
if (metadata.options.toClassOnly === true && metadata.options.toPlainOnly === true)
|
|
return true;
|
|
if (metadata.options.toClassOnly === true) {
|
|
return (transformationType === exports.TransformationType.CLASS_TO_CLASS ||
|
|
transformationType === exports.TransformationType.PLAIN_TO_CLASS);
|
|
}
|
|
if (metadata.options.toPlainOnly === true) {
|
|
return transformationType === exports.TransformationType.CLASS_TO_PLAIN;
|
|
}
|
|
return true;
|
|
})
|
|
.map(function (metadata) { return metadata.propertyName; });
|
|
};
|
|
MetadataStorage.prototype.getExcludedProperties = function (target, transformationType) {
|
|
return this.getExcludedMetadatas(target)
|
|
.filter(function (metadata) {
|
|
if (!metadata.options)
|
|
return true;
|
|
if (metadata.options.toClassOnly === true && metadata.options.toPlainOnly === true)
|
|
return true;
|
|
if (metadata.options.toClassOnly === true) {
|
|
return (transformationType === exports.TransformationType.CLASS_TO_CLASS ||
|
|
transformationType === exports.TransformationType.PLAIN_TO_CLASS);
|
|
}
|
|
if (metadata.options.toPlainOnly === true) {
|
|
return transformationType === exports.TransformationType.CLASS_TO_PLAIN;
|
|
}
|
|
return true;
|
|
})
|
|
.map(function (metadata) { return metadata.propertyName; });
|
|
};
|
|
MetadataStorage.prototype.clear = function () {
|
|
this._typeMetadatas.clear();
|
|
this._exposeMetadatas.clear();
|
|
this._excludeMetadatas.clear();
|
|
this._ancestorsMap.clear();
|
|
};
|
|
// -------------------------------------------------------------------------
|
|
// Private Methods
|
|
// -------------------------------------------------------------------------
|
|
MetadataStorage.prototype.getMetadata = function (metadatas, target) {
|
|
var metadataFromTargetMap = metadatas.get(target);
|
|
var metadataFromTarget;
|
|
if (metadataFromTargetMap) {
|
|
metadataFromTarget = Array.from(metadataFromTargetMap.values()).filter(function (meta) { return meta.propertyName !== undefined; });
|
|
}
|
|
var metadataFromAncestors = [];
|
|
for (var _i = 0, _a = this.getAncestors(target); _i < _a.length; _i++) {
|
|
var ancestor = _a[_i];
|
|
var ancestorMetadataMap = metadatas.get(ancestor);
|
|
if (ancestorMetadataMap) {
|
|
var metadataFromAncestor = Array.from(ancestorMetadataMap.values()).filter(function (meta) { return meta.propertyName !== undefined; });
|
|
metadataFromAncestors.push.apply(metadataFromAncestors, metadataFromAncestor);
|
|
}
|
|
}
|
|
return metadataFromAncestors.concat(metadataFromTarget || []);
|
|
};
|
|
MetadataStorage.prototype.findMetadata = function (metadatas, target, propertyName) {
|
|
var metadataFromTargetMap = metadatas.get(target);
|
|
if (metadataFromTargetMap) {
|
|
var metadataFromTarget = metadataFromTargetMap.get(propertyName);
|
|
if (metadataFromTarget) {
|
|
return metadataFromTarget;
|
|
}
|
|
}
|
|
for (var _i = 0, _a = this.getAncestors(target); _i < _a.length; _i++) {
|
|
var ancestor = _a[_i];
|
|
var ancestorMetadataMap = metadatas.get(ancestor);
|
|
if (ancestorMetadataMap) {
|
|
var ancestorResult = ancestorMetadataMap.get(propertyName);
|
|
if (ancestorResult) {
|
|
return ancestorResult;
|
|
}
|
|
}
|
|
}
|
|
return undefined;
|
|
};
|
|
MetadataStorage.prototype.findMetadatas = function (metadatas, target, propertyName) {
|
|
var metadataFromTargetMap = metadatas.get(target);
|
|
var metadataFromTarget;
|
|
if (metadataFromTargetMap) {
|
|
metadataFromTarget = metadataFromTargetMap.get(propertyName);
|
|
}
|
|
var metadataFromAncestorsTarget = [];
|
|
for (var _i = 0, _a = this.getAncestors(target); _i < _a.length; _i++) {
|
|
var ancestor = _a[_i];
|
|
var ancestorMetadataMap = metadatas.get(ancestor);
|
|
if (ancestorMetadataMap) {
|
|
if (ancestorMetadataMap.has(propertyName)) {
|
|
metadataFromAncestorsTarget.push.apply(metadataFromAncestorsTarget, ancestorMetadataMap.get(propertyName));
|
|
}
|
|
}
|
|
}
|
|
return metadataFromAncestorsTarget
|
|
.slice()
|
|
.reverse()
|
|
.concat((metadataFromTarget || []).slice().reverse());
|
|
};
|
|
MetadataStorage.prototype.getAncestors = function (target) {
|
|
if (!target)
|
|
return [];
|
|
if (!this._ancestorsMap.has(target)) {
|
|
var ancestors = [];
|
|
for (var baseClass = Object.getPrototypeOf(target.prototype.constructor); typeof baseClass.prototype !== 'undefined'; baseClass = Object.getPrototypeOf(baseClass.prototype.constructor)) {
|
|
ancestors.push(baseClass);
|
|
}
|
|
this._ancestorsMap.set(target, ancestors);
|
|
}
|
|
return this._ancestorsMap.get(target);
|
|
};
|
|
return MetadataStorage;
|
|
}());
|
|
|
|
/**
|
|
* Default metadata storage is used as singleton and can be used to storage all metadatas.
|
|
*/
|
|
var defaultMetadataStorage = new MetadataStorage();
|
|
|
|
/**
|
|
* This function returns the global object across Node and browsers.
|
|
*
|
|
* Note: `globalThis` is the standardized approach however it has been added to
|
|
* Node.js in version 12. We need to include this snippet until Node 12 EOL.
|
|
*/
|
|
function getGlobal() {
|
|
if (typeof globalThis !== 'undefined') {
|
|
return globalThis;
|
|
}
|
|
if (typeof global !== 'undefined') {
|
|
return global;
|
|
}
|
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
// @ts-ignore: Cannot find name 'window'.
|
|
if (typeof window !== 'undefined') {
|
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
// @ts-ignore: Cannot find name 'window'.
|
|
return window;
|
|
}
|
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
// @ts-ignore: Cannot find name 'self'.
|
|
if (typeof self !== 'undefined') {
|
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
// @ts-ignore: Cannot find name 'self'.
|
|
return self;
|
|
}
|
|
}
|
|
|
|
function isPromise(p) {
|
|
return p !== null && typeof p === 'object' && typeof p.then === 'function';
|
|
}
|
|
|
|
var __spreadArray = (undefined && undefined.__spreadArray) || function (to, from, pack) {
|
|
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
|
if (ar || !(i in from)) {
|
|
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
|
ar[i] = from[i];
|
|
}
|
|
}
|
|
return to.concat(ar || Array.prototype.slice.call(from));
|
|
};
|
|
function instantiateArrayType(arrayType) {
|
|
var array = new arrayType();
|
|
if (!(array instanceof Set) && !('push' in array)) {
|
|
return [];
|
|
}
|
|
return array;
|
|
}
|
|
var TransformOperationExecutor = /** @class */ (function () {
|
|
// -------------------------------------------------------------------------
|
|
// Constructor
|
|
// -------------------------------------------------------------------------
|
|
function TransformOperationExecutor(transformationType, options) {
|
|
this.transformationType = transformationType;
|
|
this.options = options;
|
|
// -------------------------------------------------------------------------
|
|
// Private Properties
|
|
// -------------------------------------------------------------------------
|
|
this.recursionStack = new Set();
|
|
}
|
|
// -------------------------------------------------------------------------
|
|
// Public Methods
|
|
// -------------------------------------------------------------------------
|
|
TransformOperationExecutor.prototype.transform = function (source, value, targetType, arrayType, isMap, level) {
|
|
var _this = this;
|
|
if (level === void 0) { level = 0; }
|
|
if (Array.isArray(value) || value instanceof Set) {
|
|
var newValue_1 = arrayType && this.transformationType === exports.TransformationType.PLAIN_TO_CLASS
|
|
? instantiateArrayType(arrayType)
|
|
: [];
|
|
value.forEach(function (subValue, index) {
|
|
var subSource = source ? source[index] : undefined;
|
|
if (!_this.options.enableCircularCheck || !_this.isCircular(subValue)) {
|
|
var realTargetType = void 0;
|
|
if (typeof targetType !== 'function' &&
|
|
targetType &&
|
|
targetType.options &&
|
|
targetType.options.discriminator &&
|
|
targetType.options.discriminator.property &&
|
|
targetType.options.discriminator.subTypes) {
|
|
if (_this.transformationType === exports.TransformationType.PLAIN_TO_CLASS) {
|
|
realTargetType = targetType.options.discriminator.subTypes.find(function (subType) {
|
|
return subType.name === subValue[targetType.options.discriminator.property];
|
|
});
|
|
var options = { newObject: newValue_1, object: subValue, property: undefined };
|
|
var newType = targetType.typeFunction(options);
|
|
realTargetType === undefined ? (realTargetType = newType) : (realTargetType = realTargetType.value);
|
|
if (!targetType.options.keepDiscriminatorProperty)
|
|
delete subValue[targetType.options.discriminator.property];
|
|
}
|
|
if (_this.transformationType === exports.TransformationType.CLASS_TO_CLASS) {
|
|
realTargetType = subValue.constructor;
|
|
}
|
|
if (_this.transformationType === exports.TransformationType.CLASS_TO_PLAIN) {
|
|
subValue[targetType.options.discriminator.property] = targetType.options.discriminator.subTypes.find(function (subType) { return subType.value === subValue.constructor; }).name;
|
|
}
|
|
}
|
|
else {
|
|
realTargetType = targetType;
|
|
}
|
|
var value_1 = _this.transform(subSource, subValue, realTargetType, undefined, subValue instanceof Map, level + 1);
|
|
if (newValue_1 instanceof Set) {
|
|
newValue_1.add(value_1);
|
|
}
|
|
else {
|
|
newValue_1.push(value_1);
|
|
}
|
|
}
|
|
else if (_this.transformationType === exports.TransformationType.CLASS_TO_CLASS) {
|
|
if (newValue_1 instanceof Set) {
|
|
newValue_1.add(subValue);
|
|
}
|
|
else {
|
|
newValue_1.push(subValue);
|
|
}
|
|
}
|
|
});
|
|
return newValue_1;
|
|
}
|
|
else if (targetType === String && !isMap) {
|
|
if (value === null || value === undefined)
|
|
return value;
|
|
return String(value);
|
|
}
|
|
else if (targetType === Number && !isMap) {
|
|
if (value === null || value === undefined)
|
|
return value;
|
|
return Number(value);
|
|
}
|
|
else if (targetType === Boolean && !isMap) {
|
|
if (value === null || value === undefined)
|
|
return value;
|
|
return Boolean(value);
|
|
}
|
|
else if ((targetType === Date || value instanceof Date) && !isMap) {
|
|
if (value instanceof Date) {
|
|
return new Date(value.valueOf());
|
|
}
|
|
if (value === null || value === undefined)
|
|
return value;
|
|
return new Date(value);
|
|
}
|
|
else if (!!getGlobal().Buffer && (targetType === Buffer || value instanceof Buffer) && !isMap) {
|
|
if (value === null || value === undefined)
|
|
return value;
|
|
return Buffer.from(value);
|
|
}
|
|
else if (isPromise(value) && !isMap) {
|
|
return new Promise(function (resolve, reject) {
|
|
value.then(function (data) { return resolve(_this.transform(undefined, data, targetType, undefined, undefined, level + 1)); }, reject);
|
|
});
|
|
}
|
|
else if (!isMap && value !== null && typeof value === 'object' && typeof value.then === 'function') {
|
|
// Note: We should not enter this, as promise has been handled above
|
|
// This option simply returns the Promise preventing a JS error from happening and should be an inaccessible path.
|
|
return value; // skip promise transformation
|
|
}
|
|
else if (typeof value === 'object' && value !== null) {
|
|
// try to guess the type
|
|
if (!targetType && value.constructor !== Object /* && TransformationType === TransformationType.CLASS_TO_PLAIN*/)
|
|
if (!Array.isArray(value) && value.constructor === Array) ;
|
|
else {
|
|
// We are good we can use the built-in constructor
|
|
targetType = value.constructor;
|
|
}
|
|
if (!targetType && source)
|
|
targetType = source.constructor;
|
|
if (this.options.enableCircularCheck) {
|
|
// add transformed type to prevent circular references
|
|
this.recursionStack.add(value);
|
|
}
|
|
var keys = this.getKeys(targetType, value, isMap);
|
|
var newValue = source ? source : {};
|
|
if (!source &&
|
|
(this.transformationType === exports.TransformationType.PLAIN_TO_CLASS ||
|
|
this.transformationType === exports.TransformationType.CLASS_TO_CLASS)) {
|
|
if (isMap) {
|
|
newValue = new Map();
|
|
}
|
|
else if (targetType) {
|
|
newValue = new targetType();
|
|
}
|
|
else {
|
|
newValue = {};
|
|
}
|
|
}
|
|
var _loop_1 = function (key) {
|
|
if (key === '__proto__' || key === 'constructor') {
|
|
return "continue";
|
|
}
|
|
var valueKey = key;
|
|
var newValueKey = key, propertyName = key;
|
|
if (!this_1.options.ignoreDecorators && targetType) {
|
|
if (this_1.transformationType === exports.TransformationType.PLAIN_TO_CLASS) {
|
|
var exposeMetadata = defaultMetadataStorage.findExposeMetadataByCustomName(targetType, key);
|
|
if (exposeMetadata) {
|
|
propertyName = exposeMetadata.propertyName;
|
|
newValueKey = exposeMetadata.propertyName;
|
|
}
|
|
}
|
|
else if (this_1.transformationType === exports.TransformationType.CLASS_TO_PLAIN ||
|
|
this_1.transformationType === exports.TransformationType.CLASS_TO_CLASS) {
|
|
var exposeMetadata = defaultMetadataStorage.findExposeMetadata(targetType, key);
|
|
if (exposeMetadata && exposeMetadata.options && exposeMetadata.options.name) {
|
|
newValueKey = exposeMetadata.options.name;
|
|
}
|
|
}
|
|
}
|
|
// get a subvalue
|
|
var subValue = undefined;
|
|
if (this_1.transformationType === exports.TransformationType.PLAIN_TO_CLASS) {
|
|
/**
|
|
* This section is added for the following report:
|
|
* https://github.com/typestack/class-transformer/issues/596
|
|
*
|
|
* We should not call functions or constructors when transforming to class.
|
|
*/
|
|
subValue = value[valueKey];
|
|
}
|
|
else {
|
|
if (value instanceof Map) {
|
|
subValue = value.get(valueKey);
|
|
}
|
|
else if (value[valueKey] instanceof Function) {
|
|
subValue = value[valueKey]();
|
|
}
|
|
else {
|
|
subValue = value[valueKey];
|
|
}
|
|
}
|
|
// determine a type
|
|
var type = undefined, isSubValueMap = subValue instanceof Map;
|
|
if (targetType && isMap) {
|
|
type = targetType;
|
|
}
|
|
else if (targetType) {
|
|
var metadata_1 = defaultMetadataStorage.findTypeMetadata(targetType, propertyName);
|
|
if (metadata_1) {
|
|
var options = { newObject: newValue, object: value, property: propertyName };
|
|
var newType = metadata_1.typeFunction ? metadata_1.typeFunction(options) : metadata_1.reflectedType;
|
|
if (metadata_1.options &&
|
|
metadata_1.options.discriminator &&
|
|
metadata_1.options.discriminator.property &&
|
|
metadata_1.options.discriminator.subTypes) {
|
|
if (!(value[valueKey] instanceof Array)) {
|
|
if (this_1.transformationType === exports.TransformationType.PLAIN_TO_CLASS) {
|
|
type = metadata_1.options.discriminator.subTypes.find(function (subType) {
|
|
if (subValue && subValue instanceof Object && metadata_1.options.discriminator.property in subValue) {
|
|
return subType.name === subValue[metadata_1.options.discriminator.property];
|
|
}
|
|
});
|
|
type === undefined ? (type = newType) : (type = type.value);
|
|
if (!metadata_1.options.keepDiscriminatorProperty) {
|
|
if (subValue && subValue instanceof Object && metadata_1.options.discriminator.property in subValue) {
|
|
delete subValue[metadata_1.options.discriminator.property];
|
|
}
|
|
}
|
|
}
|
|
if (this_1.transformationType === exports.TransformationType.CLASS_TO_CLASS) {
|
|
type = subValue.constructor;
|
|
}
|
|
if (this_1.transformationType === exports.TransformationType.CLASS_TO_PLAIN) {
|
|
if (subValue) {
|
|
subValue[metadata_1.options.discriminator.property] = metadata_1.options.discriminator.subTypes.find(function (subType) { return subType.value === subValue.constructor; }).name;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
type = metadata_1;
|
|
}
|
|
}
|
|
else {
|
|
type = newType;
|
|
}
|
|
isSubValueMap = isSubValueMap || metadata_1.reflectedType === Map;
|
|
}
|
|
else if (this_1.options.targetMaps) {
|
|
// try to find a type in target maps
|
|
this_1.options.targetMaps
|
|
.filter(function (map) { return map.target === targetType && !!map.properties[propertyName]; })
|
|
.forEach(function (map) { return (type = map.properties[propertyName]); });
|
|
}
|
|
else if (this_1.options.enableImplicitConversion &&
|
|
this_1.transformationType === exports.TransformationType.PLAIN_TO_CLASS) {
|
|
// if we have no registererd type via the @Type() decorator then we check if we have any
|
|
// type declarations in reflect-metadata (type declaration is emited only if some decorator is added to the property.)
|
|
var reflectedType = Reflect.getMetadata('design:type', targetType.prototype, propertyName);
|
|
if (reflectedType) {
|
|
type = reflectedType;
|
|
}
|
|
}
|
|
}
|
|
// if value is an array try to get its custom array type
|
|
var arrayType_1 = Array.isArray(value[valueKey])
|
|
? this_1.getReflectedType(targetType, propertyName)
|
|
: undefined;
|
|
// const subValueKey = TransformationType === TransformationType.PLAIN_TO_CLASS && newKeyName ? newKeyName : key;
|
|
var subSource = source ? source[valueKey] : undefined;
|
|
// if its deserialization then type if required
|
|
// if we uncomment this types like string[] will not work
|
|
// if (this.transformationType === TransformationType.PLAIN_TO_CLASS && !type && subValue instanceof Object && !(subValue instanceof Date))
|
|
// throw new Error(`Cannot determine type for ${(targetType as any).name }.${propertyName}, did you forget to specify a @Type?`);
|
|
// if newValue is a source object that has method that match newKeyName then skip it
|
|
if (newValue.constructor.prototype) {
|
|
var descriptor = Object.getOwnPropertyDescriptor(newValue.constructor.prototype, newValueKey);
|
|
if ((this_1.transformationType === exports.TransformationType.PLAIN_TO_CLASS ||
|
|
this_1.transformationType === exports.TransformationType.CLASS_TO_CLASS) &&
|
|
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
((descriptor && !descriptor.set) || newValue[newValueKey] instanceof Function))
|
|
return "continue";
|
|
}
|
|
if (!this_1.options.enableCircularCheck || !this_1.isCircular(subValue)) {
|
|
var transformKey = this_1.transformationType === exports.TransformationType.PLAIN_TO_CLASS ? newValueKey : key;
|
|
var finalValue = void 0;
|
|
if (this_1.transformationType === exports.TransformationType.CLASS_TO_PLAIN) {
|
|
// Get original value
|
|
finalValue = value[transformKey];
|
|
// Apply custom transformation
|
|
finalValue = this_1.applyCustomTransformations(finalValue, targetType, transformKey, value, this_1.transformationType);
|
|
// If nothing change, it means no custom transformation was applied, so use the subValue.
|
|
finalValue = value[transformKey] === finalValue ? subValue : finalValue;
|
|
// Apply the default transformation
|
|
finalValue = this_1.transform(subSource, finalValue, type, arrayType_1, isSubValueMap, level + 1);
|
|
}
|
|
else {
|
|
if (subValue === undefined && this_1.options.exposeDefaultValues) {
|
|
// Set default value if nothing provided
|
|
finalValue = newValue[newValueKey];
|
|
}
|
|
else {
|
|
finalValue = this_1.transform(subSource, subValue, type, arrayType_1, isSubValueMap, level + 1);
|
|
finalValue = this_1.applyCustomTransformations(finalValue, targetType, transformKey, value, this_1.transformationType);
|
|
}
|
|
}
|
|
if (finalValue !== undefined || this_1.options.exposeUnsetFields) {
|
|
if (newValue instanceof Map) {
|
|
newValue.set(newValueKey, finalValue);
|
|
}
|
|
else {
|
|
newValue[newValueKey] = finalValue;
|
|
}
|
|
}
|
|
}
|
|
else if (this_1.transformationType === exports.TransformationType.CLASS_TO_CLASS) {
|
|
var finalValue = subValue;
|
|
finalValue = this_1.applyCustomTransformations(finalValue, targetType, key, value, this_1.transformationType);
|
|
if (finalValue !== undefined || this_1.options.exposeUnsetFields) {
|
|
if (newValue instanceof Map) {
|
|
newValue.set(newValueKey, finalValue);
|
|
}
|
|
else {
|
|
newValue[newValueKey] = finalValue;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
var this_1 = this;
|
|
// traverse over keys
|
|
for (var _i = 0, keys_1 = keys; _i < keys_1.length; _i++) {
|
|
var key = keys_1[_i];
|
|
_loop_1(key);
|
|
}
|
|
if (this.options.enableCircularCheck) {
|
|
this.recursionStack.delete(value);
|
|
}
|
|
return newValue;
|
|
}
|
|
else {
|
|
return value;
|
|
}
|
|
};
|
|
TransformOperationExecutor.prototype.applyCustomTransformations = function (value, target, key, obj, transformationType) {
|
|
var _this = this;
|
|
var metadatas = defaultMetadataStorage.findTransformMetadatas(target, key, this.transformationType);
|
|
// apply versioning options
|
|
if (this.options.version !== undefined) {
|
|
metadatas = metadatas.filter(function (metadata) {
|
|
if (!metadata.options)
|
|
return true;
|
|
return _this.checkVersion(metadata.options.since, metadata.options.until);
|
|
});
|
|
}
|
|
// apply grouping options
|
|
if (this.options.groups && this.options.groups.length) {
|
|
metadatas = metadatas.filter(function (metadata) {
|
|
if (!metadata.options)
|
|
return true;
|
|
return _this.checkGroups(metadata.options.groups);
|
|
});
|
|
}
|
|
else {
|
|
metadatas = metadatas.filter(function (metadata) {
|
|
return !metadata.options || !metadata.options.groups || !metadata.options.groups.length;
|
|
});
|
|
}
|
|
metadatas.forEach(function (metadata) {
|
|
value = metadata.transformFn({ value: value, key: key, obj: obj, type: transformationType, options: _this.options });
|
|
});
|
|
return value;
|
|
};
|
|
// preventing circular references
|
|
TransformOperationExecutor.prototype.isCircular = function (object) {
|
|
return this.recursionStack.has(object);
|
|
};
|
|
TransformOperationExecutor.prototype.getReflectedType = function (target, propertyName) {
|
|
if (!target)
|
|
return undefined;
|
|
var meta = defaultMetadataStorage.findTypeMetadata(target, propertyName);
|
|
return meta ? meta.reflectedType : undefined;
|
|
};
|
|
TransformOperationExecutor.prototype.getKeys = function (target, object, isMap) {
|
|
var _this = this;
|
|
// determine exclusion strategy
|
|
var strategy = defaultMetadataStorage.getStrategy(target);
|
|
if (strategy === 'none')
|
|
strategy = this.options.strategy || 'exposeAll'; // exposeAll is default strategy
|
|
// get all keys that need to expose
|
|
var keys = [];
|
|
if (strategy === 'exposeAll' || isMap) {
|
|
if (object instanceof Map) {
|
|
keys = Array.from(object.keys());
|
|
}
|
|
else {
|
|
keys = Object.keys(object);
|
|
}
|
|
}
|
|
if (isMap) {
|
|
// expose & exclude do not apply for map keys only to fields
|
|
return keys;
|
|
}
|
|
/**
|
|
* If decorators are ignored but we don't want the extraneous values, then we use the
|
|
* metadata to decide which property is needed, but doesn't apply the decorator effect.
|
|
*/
|
|
if (this.options.ignoreDecorators && this.options.excludeExtraneousValues && target) {
|
|
var exposedProperties = defaultMetadataStorage.getExposedProperties(target, this.transformationType);
|
|
var excludedProperties = defaultMetadataStorage.getExcludedProperties(target, this.transformationType);
|
|
keys = __spreadArray(__spreadArray([], exposedProperties, true), excludedProperties, true);
|
|
}
|
|
if (!this.options.ignoreDecorators && target) {
|
|
// add all exposed to list of keys
|
|
var exposedProperties = defaultMetadataStorage.getExposedProperties(target, this.transformationType);
|
|
if (this.transformationType === exports.TransformationType.PLAIN_TO_CLASS) {
|
|
exposedProperties = exposedProperties.map(function (key) {
|
|
var exposeMetadata = defaultMetadataStorage.findExposeMetadata(target, key);
|
|
if (exposeMetadata && exposeMetadata.options && exposeMetadata.options.name) {
|
|
return exposeMetadata.options.name;
|
|
}
|
|
return key;
|
|
});
|
|
}
|
|
if (this.options.excludeExtraneousValues) {
|
|
keys = exposedProperties;
|
|
}
|
|
else {
|
|
keys = keys.concat(exposedProperties);
|
|
}
|
|
// exclude excluded properties
|
|
var excludedProperties_1 = defaultMetadataStorage.getExcludedProperties(target, this.transformationType);
|
|
if (excludedProperties_1.length > 0) {
|
|
keys = keys.filter(function (key) {
|
|
return !excludedProperties_1.includes(key);
|
|
});
|
|
}
|
|
// apply versioning options
|
|
if (this.options.version !== undefined) {
|
|
keys = keys.filter(function (key) {
|
|
var exposeMetadata = defaultMetadataStorage.findExposeMetadata(target, key);
|
|
if (!exposeMetadata || !exposeMetadata.options)
|
|
return true;
|
|
return _this.checkVersion(exposeMetadata.options.since, exposeMetadata.options.until);
|
|
});
|
|
}
|
|
// apply grouping options
|
|
if (this.options.groups && this.options.groups.length) {
|
|
keys = keys.filter(function (key) {
|
|
var exposeMetadata = defaultMetadataStorage.findExposeMetadata(target, key);
|
|
if (!exposeMetadata || !exposeMetadata.options)
|
|
return true;
|
|
return _this.checkGroups(exposeMetadata.options.groups);
|
|
});
|
|
}
|
|
else {
|
|
keys = keys.filter(function (key) {
|
|
var exposeMetadata = defaultMetadataStorage.findExposeMetadata(target, key);
|
|
return (!exposeMetadata ||
|
|
!exposeMetadata.options ||
|
|
!exposeMetadata.options.groups ||
|
|
!exposeMetadata.options.groups.length);
|
|
});
|
|
}
|
|
}
|
|
// exclude prefixed properties
|
|
if (this.options.excludePrefixes && this.options.excludePrefixes.length) {
|
|
keys = keys.filter(function (key) {
|
|
return _this.options.excludePrefixes.every(function (prefix) {
|
|
return key.substr(0, prefix.length) !== prefix;
|
|
});
|
|
});
|
|
}
|
|
// make sure we have unique keys
|
|
keys = keys.filter(function (key, index, self) {
|
|
return self.indexOf(key) === index;
|
|
});
|
|
return keys;
|
|
};
|
|
TransformOperationExecutor.prototype.checkVersion = function (since, until) {
|
|
var decision = true;
|
|
if (decision && since)
|
|
decision = this.options.version >= since;
|
|
if (decision && until)
|
|
decision = this.options.version < until;
|
|
return decision;
|
|
};
|
|
TransformOperationExecutor.prototype.checkGroups = function (groups) {
|
|
if (!groups)
|
|
return true;
|
|
return this.options.groups.some(function (optionGroup) { return groups.includes(optionGroup); });
|
|
};
|
|
return TransformOperationExecutor;
|
|
}());
|
|
|
|
/**
|
|
* These are the default options used by any transformation operation.
|
|
*/
|
|
var defaultOptions = {
|
|
enableCircularCheck: false,
|
|
enableImplicitConversion: false,
|
|
excludeExtraneousValues: false,
|
|
excludePrefixes: undefined,
|
|
exposeDefaultValues: false,
|
|
exposeUnsetFields: true,
|
|
groups: undefined,
|
|
ignoreDecorators: false,
|
|
strategy: undefined,
|
|
targetMaps: undefined,
|
|
version: undefined,
|
|
};
|
|
|
|
var __assign = (undefined && undefined.__assign) || function () {
|
|
__assign = Object.assign || function(t) {
|
|
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
s = arguments[i];
|
|
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
t[p] = s[p];
|
|
}
|
|
return t;
|
|
};
|
|
return __assign.apply(this, arguments);
|
|
};
|
|
var ClassTransformer = /** @class */ (function () {
|
|
function ClassTransformer() {
|
|
}
|
|
ClassTransformer.prototype.instanceToPlain = function (object, options) {
|
|
var executor = new TransformOperationExecutor(exports.TransformationType.CLASS_TO_PLAIN, __assign(__assign({}, defaultOptions), options));
|
|
return executor.transform(undefined, object, undefined, undefined, undefined, undefined);
|
|
};
|
|
ClassTransformer.prototype.classToPlainFromExist = function (object, plainObject, options) {
|
|
var executor = new TransformOperationExecutor(exports.TransformationType.CLASS_TO_PLAIN, __assign(__assign({}, defaultOptions), options));
|
|
return executor.transform(plainObject, object, undefined, undefined, undefined, undefined);
|
|
};
|
|
ClassTransformer.prototype.plainToInstance = function (cls, plain, options) {
|
|
var executor = new TransformOperationExecutor(exports.TransformationType.PLAIN_TO_CLASS, __assign(__assign({}, defaultOptions), options));
|
|
return executor.transform(undefined, plain, cls, undefined, undefined, undefined);
|
|
};
|
|
ClassTransformer.prototype.plainToClassFromExist = function (clsObject, plain, options) {
|
|
var executor = new TransformOperationExecutor(exports.TransformationType.PLAIN_TO_CLASS, __assign(__assign({}, defaultOptions), options));
|
|
return executor.transform(clsObject, plain, undefined, undefined, undefined, undefined);
|
|
};
|
|
ClassTransformer.prototype.instanceToInstance = function (object, options) {
|
|
var executor = new TransformOperationExecutor(exports.TransformationType.CLASS_TO_CLASS, __assign(__assign({}, defaultOptions), options));
|
|
return executor.transform(undefined, object, undefined, undefined, undefined, undefined);
|
|
};
|
|
ClassTransformer.prototype.classToClassFromExist = function (object, fromObject, options) {
|
|
var executor = new TransformOperationExecutor(exports.TransformationType.CLASS_TO_CLASS, __assign(__assign({}, defaultOptions), options));
|
|
return executor.transform(fromObject, object, undefined, undefined, undefined, undefined);
|
|
};
|
|
ClassTransformer.prototype.serialize = function (object, options) {
|
|
return JSON.stringify(this.instanceToPlain(object, options));
|
|
};
|
|
/**
|
|
* Deserializes given JSON string to a object of the given class.
|
|
*/
|
|
ClassTransformer.prototype.deserialize = function (cls, json, options) {
|
|
var jsonObject = JSON.parse(json);
|
|
return this.plainToInstance(cls, jsonObject, options);
|
|
};
|
|
/**
|
|
* Deserializes given JSON string to an array of objects of the given class.
|
|
*/
|
|
ClassTransformer.prototype.deserializeArray = function (cls, json, options) {
|
|
var jsonObject = JSON.parse(json);
|
|
return this.plainToInstance(cls, jsonObject, options);
|
|
};
|
|
return ClassTransformer;
|
|
}());
|
|
|
|
/**
|
|
* Marks the given class or property as excluded. By default the property is excluded in both
|
|
* constructorToPlain and plainToConstructor transformations. It can be limited to only one direction
|
|
* via using the `toPlainOnly` or `toClassOnly` option.
|
|
*
|
|
* Can be applied to class definitions and properties.
|
|
*/
|
|
function Exclude(options) {
|
|
if (options === void 0) { options = {}; }
|
|
/**
|
|
* NOTE: The `propertyName` property must be marked as optional because
|
|
* this decorator used both as a class and a property decorator and the
|
|
* Typescript compiler will freak out if we make it mandatory as a class
|
|
* decorator only receives one parameter.
|
|
*/
|
|
return function (object, propertyName) {
|
|
defaultMetadataStorage.addExcludeMetadata({
|
|
target: object instanceof Function ? object : object.constructor,
|
|
propertyName: propertyName,
|
|
options: options,
|
|
});
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Marks the given class or property as included. By default the property is included in both
|
|
* constructorToPlain and plainToConstructor transformations. It can be limited to only one direction
|
|
* via using the `toPlainOnly` or `toClassOnly` option.
|
|
*
|
|
* Can be applied to class definitions and properties.
|
|
*/
|
|
function Expose(options) {
|
|
if (options === void 0) { options = {}; }
|
|
/**
|
|
* NOTE: The `propertyName` property must be marked as optional because
|
|
* this decorator used both as a class and a property decorator and the
|
|
* Typescript compiler will freak out if we make it mandatory as a class
|
|
* decorator only receives one parameter.
|
|
*/
|
|
return function (object, propertyName) {
|
|
defaultMetadataStorage.addExposeMetadata({
|
|
target: object instanceof Function ? object : object.constructor,
|
|
propertyName: propertyName,
|
|
options: options,
|
|
});
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Return the class instance only with the exposed properties.
|
|
*
|
|
* Can be applied to functions and getters/setters only.
|
|
*/
|
|
function TransformInstanceToInstance(params) {
|
|
return function (target, propertyKey, descriptor) {
|
|
var classTransformer = new ClassTransformer();
|
|
var originalMethod = descriptor.value;
|
|
descriptor.value = function () {
|
|
var args = [];
|
|
for (var _i = 0; _i < arguments.length; _i++) {
|
|
args[_i] = arguments[_i];
|
|
}
|
|
var result = originalMethod.apply(this, args);
|
|
var isPromise = !!result && (typeof result === 'object' || typeof result === 'function') && typeof result.then === 'function';
|
|
return isPromise
|
|
? result.then(function (data) { return classTransformer.instanceToInstance(data, params); })
|
|
: classTransformer.instanceToInstance(result, params);
|
|
};
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Transform the object from class to plain object and return only with the exposed properties.
|
|
*
|
|
* Can be applied to functions and getters/setters only.
|
|
*/
|
|
function TransformInstanceToPlain(params) {
|
|
return function (target, propertyKey, descriptor) {
|
|
var classTransformer = new ClassTransformer();
|
|
var originalMethod = descriptor.value;
|
|
descriptor.value = function () {
|
|
var args = [];
|
|
for (var _i = 0; _i < arguments.length; _i++) {
|
|
args[_i] = arguments[_i];
|
|
}
|
|
var result = originalMethod.apply(this, args);
|
|
var isPromise = !!result && (typeof result === 'object' || typeof result === 'function') && typeof result.then === 'function';
|
|
return isPromise
|
|
? result.then(function (data) { return classTransformer.instanceToPlain(data, params); })
|
|
: classTransformer.instanceToPlain(result, params);
|
|
};
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Return the class instance only with the exposed properties.
|
|
*
|
|
* Can be applied to functions and getters/setters only.
|
|
*/
|
|
function TransformPlainToInstance(classType, params) {
|
|
return function (target, propertyKey, descriptor) {
|
|
var classTransformer = new ClassTransformer();
|
|
var originalMethod = descriptor.value;
|
|
descriptor.value = function () {
|
|
var args = [];
|
|
for (var _i = 0; _i < arguments.length; _i++) {
|
|
args[_i] = arguments[_i];
|
|
}
|
|
var result = originalMethod.apply(this, args);
|
|
var isPromise = !!result && (typeof result === 'object' || typeof result === 'function') && typeof result.then === 'function';
|
|
return isPromise
|
|
? result.then(function (data) { return classTransformer.plainToInstance(classType, data, params); })
|
|
: classTransformer.plainToInstance(classType, result, params);
|
|
};
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Defines a custom logic for value transformation.
|
|
*
|
|
* Can be applied to properties only.
|
|
*/
|
|
function Transform(transformFn, options) {
|
|
if (options === void 0) { options = {}; }
|
|
return function (target, propertyName) {
|
|
defaultMetadataStorage.addTransformMetadata({
|
|
target: target.constructor,
|
|
propertyName: propertyName,
|
|
transformFn: transformFn,
|
|
options: options,
|
|
});
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Specifies a type of the property.
|
|
* The given TypeFunction can return a constructor. A discriminator can be given in the options.
|
|
*
|
|
* Can be applied to properties only.
|
|
*/
|
|
function Type(typeFunction, options) {
|
|
if (options === void 0) { options = {}; }
|
|
return function (target, propertyName) {
|
|
var reflectedType = Reflect.getMetadata('design:type', target, propertyName);
|
|
defaultMetadataStorage.addTypeMetadata({
|
|
target: target.constructor,
|
|
propertyName: propertyName,
|
|
reflectedType: reflectedType,
|
|
typeFunction: typeFunction,
|
|
options: options,
|
|
});
|
|
};
|
|
}
|
|
|
|
var classTransformer = new ClassTransformer();
|
|
function classToPlain(object, options) {
|
|
return classTransformer.instanceToPlain(object, options);
|
|
}
|
|
function instanceToPlain(object, options) {
|
|
return classTransformer.instanceToPlain(object, options);
|
|
}
|
|
function classToPlainFromExist(object, plainObject, options) {
|
|
return classTransformer.classToPlainFromExist(object, plainObject, options);
|
|
}
|
|
function plainToClass(cls, plain, options) {
|
|
return classTransformer.plainToInstance(cls, plain, options);
|
|
}
|
|
function plainToInstance(cls, plain, options) {
|
|
return classTransformer.plainToInstance(cls, plain, options);
|
|
}
|
|
function plainToClassFromExist(clsObject, plain, options) {
|
|
return classTransformer.plainToClassFromExist(clsObject, plain, options);
|
|
}
|
|
function instanceToInstance(object, options) {
|
|
return classTransformer.instanceToInstance(object, options);
|
|
}
|
|
function classToClassFromExist(object, fromObject, options) {
|
|
return classTransformer.classToClassFromExist(object, fromObject, options);
|
|
}
|
|
function serialize(object, options) {
|
|
return classTransformer.serialize(object, options);
|
|
}
|
|
/**
|
|
* Deserializes given JSON string to a object of the given class.
|
|
*
|
|
* @deprecated This function is being removed. Please use the following instead:
|
|
* ```
|
|
* instanceToClass(cls, JSON.parse(json), options)
|
|
* ```
|
|
*/
|
|
function deserialize(cls, json, options) {
|
|
return classTransformer.deserialize(cls, json, options);
|
|
}
|
|
/**
|
|
* Deserializes given JSON string to an array of objects of the given class.
|
|
*
|
|
* @deprecated This function is being removed. Please use the following instead:
|
|
* ```
|
|
* JSON.parse(json).map(value => instanceToClass(cls, value, options))
|
|
* ```
|
|
*
|
|
*/
|
|
function deserializeArray(cls, json, options) {
|
|
return classTransformer.deserializeArray(cls, json, options);
|
|
}
|
|
|
|
exports.ClassTransformer = ClassTransformer;
|
|
exports.Exclude = Exclude;
|
|
exports.Expose = Expose;
|
|
exports.Transform = Transform;
|
|
exports.TransformInstanceToInstance = TransformInstanceToInstance;
|
|
exports.TransformInstanceToPlain = TransformInstanceToPlain;
|
|
exports.TransformPlainToInstance = TransformPlainToInstance;
|
|
exports.Type = Type;
|
|
exports.classToClassFromExist = classToClassFromExist;
|
|
exports.classToPlain = classToPlain;
|
|
exports.classToPlainFromExist = classToPlainFromExist;
|
|
exports.deserialize = deserialize;
|
|
exports.deserializeArray = deserializeArray;
|
|
exports.instanceToInstance = instanceToInstance;
|
|
exports.instanceToPlain = instanceToPlain;
|
|
exports.plainToClass = plainToClass;
|
|
exports.plainToClassFromExist = plainToClassFromExist;
|
|
exports.plainToInstance = plainToInstance;
|
|
exports.serialize = serialize;
|
|
|
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
|
}));
|
|
//# sourceMappingURL=class-transformer.umd.js.map
|