UNPKG

airship-server

Version:

Airship is a framework for Node.JS & TypeScript that helps you to write big, scalable and maintainable API servers.

176 lines 8.03 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const ClassScheme_1 = require("../codeGen/domain/schema/ClassScheme"); const ClassField_1 = require("../codeGen/domain/schema/ClassField"); const StringType_1 = require("../codeGen/domain/types/StringType"); const NumberType_1 = require("../codeGen/domain/types/NumberType"); const BooleanType_1 = require("../codeGen/domain/types/BooleanType"); const CustomType_1 = require("../codeGen/domain/types/CustomType"); const VectorType_1 = require("../codeGen/domain/types/VectorType"); require("reflect-metadata"); const AnyType_1 = require("../codeGen/domain/types/AnyType"); const ObjectType_1 = require("../codeGen/domain/types/ObjectType"); const SerializableKey = 'SerializableKey'; const SerializableKeys = 'SerializableKeys'; const SerializableTypes = 'SerializableTypes'; const SerializableArrayTypes = 'SerializableArrayTypes'; function isSerializableObject(object) { if (object == 'any') return false; return !!object.prototype[SerializableKeys]; } function json(name, arrayType, isAny = false) { return (target, propertyKey) => { const constructor = target; name = name || propertyKey.replace('_', ''); Reflect.defineMetadata(SerializableKey, name, target, propertyKey); constructor[SerializableKeys] = constructor[SerializableKeys] || []; constructor[SerializableTypes] = constructor[SerializableTypes] || []; constructor[SerializableArrayTypes] = constructor[SerializableArrayTypes] || []; let type = Reflect.getMetadata('design:type', target, propertyKey); // we need new arrays here, because at this point they are references to super class arrays // so just pushing new values would modify super (and other child) class array constructor[SerializableKeys] = [...constructor[SerializableKeys], name]; constructor[SerializableTypes] = [...constructor[SerializableTypes], (isAny ? 'any' : type)]; constructor[SerializableArrayTypes] = [...constructor[SerializableArrayTypes], arrayType]; }; } exports.json = json; function deserialize(serializableType, raw, valuePath = []) { const serializableConstructor = serializableType.prototype; const propsNames = serializableConstructor[SerializableKeys] || []; const types = serializableConstructor[SerializableTypes]; const arrayTypes = serializableConstructor[SerializableArrayTypes]; const props = propsNames.map((prop, index) => { let type = types[index]; let arrayType = arrayTypes[index]; let isSerializable = isSerializableObject(type) == true; valuePath.push(prop); checkType(valuePath.join('.'), raw[prop], type, isSerializable); if (arrayType && isSerializableObject(arrayType) == true) { let val = raw[prop].map((v, i) => { valuePath.push(`{${i}}`); let deserialized = deserialize(arrayType, v, valuePath); valuePath.pop(); return deserialized; }); valuePath.pop(); return val; } else if (arrayType) { let val = raw[prop].map((v, i) => { valuePath.push(`{${i}}`); checkType(valuePath.join('.'), v, arrayType, false); valuePath.pop(); return v; }); valuePath.pop(); return val; } else if (isSerializable) { let val = deserialize(type, raw[prop], valuePath); valuePath.pop(); return val; } else { valuePath.pop(); return raw[prop]; } }); return new serializableConstructor.constructor(...props); } exports.deserialize = deserialize; function checkType(prop, value, expectedType, isSerializable) { if (value == undefined) throw new Error(`${prop} argument missing`); let valueType = typeof value; if (expectedType == Array && !Array.isArray(value)) throw new Error(`${prop} must be array`); if (!isSerializable) { if (expectedType == String && valueType !== 'string') throw new Error(`${prop} must be string instead of ${valueType}`); if (expectedType == Number && valueType !== 'number') throw new Error(`${prop} must be number instead of ${valueType}`); if (expectedType == Boolean && valueType !== 'boolean') throw new Error(`${prop} must be boolean instead of ${valueType}`); if (expectedType == Object && valueType !== 'object') throw new Error(`${prop} must be boolean instead of ${valueType}`); } } function serialize(entity) { let result = {}; let arrayTypes = entity[SerializableArrayTypes]; let i = 0; for (let prop in entity) { if (prop == SerializableKeys || prop == SerializableTypes || prop == SerializableArrayTypes) continue; let keyName = Reflect.getMetadata(SerializableKey, entity, prop) || prop; let type = Reflect.getMetadata('design:type', entity, prop); let arrayType = arrayTypes[i]; if (arrayType && isSerializableObject(arrayType) == true) { result[keyName] = entity[prop].map(serialize); } else if (isSerializableObject(type) == true) { result[keyName] = serialize(entity[prop]); } else result[keyName] = entity[prop]; i++; } return result; } exports.serialize = serialize; function getClassScheme(serializableType) { const serializableConstructor = serializableType.prototype; let propsNames = serializableConstructor[SerializableKeys]; const types = serializableConstructor[SerializableTypes]; const arrayTypes = serializableConstructor[SerializableArrayTypes]; let fields = []; propsNames = propsNames || []; propsNames.forEach((propName, index) => { fields.push(new ClassField_1.default(propName, getType(types[index], arrayTypes[index]), '')); }); return new ClassScheme_1.default(serializableConstructor.constructor.name, fields); } exports.getClassScheme = getClassScheme; function getType(propType, arrayType) { if (propType == String) return new StringType_1.default(); if (propType == Number) return new NumberType_1.default(); if (propType == Boolean) return new BooleanType_1.default(); if (propType == Object) return new ObjectType_1.default(); if (propType == 'any') return new AnyType_1.default(); if (isSerializableObject(propType) == true) return new CustomType_1.default(propType.prototype.constructor.name); if (propType == Array && arrayType) return new VectorType_1.default(getType(arrayType)); throw new Error(`Model scheme generation fail, unknown type: ${propType}`); } function getClassDependencies(serializableType) { const serializableConstructor = serializableType.prototype; const propsNames = serializableConstructor[SerializableKeys] || []; const types = serializableConstructor[SerializableTypes]; const arrayTypes = serializableConstructor[SerializableArrayTypes]; let dependencies = {}; let subDeps = []; propsNames.forEach((propName, index) => { if (isSerializableObject(types[index]) == true) { dependencies[types[index].prototype.constructor.name] = types[index]; subDeps = [...subDeps, ...getClassDependencies(types[index])]; } else if (arrayTypes[index] && isSerializableObject(arrayTypes[index]) == true) { dependencies[arrayTypes[index].prototype.constructor.name] = arrayTypes[index]; subDeps = [...subDeps, ...getClassDependencies(arrayTypes[index])]; } }); return [...Object.keys(dependencies).map(key => dependencies[key]), ...subDeps]; } exports.getClassDependencies = getClassDependencies; //# sourceMappingURL=Serialize.js.map