UNPKG

vagabond-uml

Version:

UML support for Vagabond via XMI and JDL files

424 lines (385 loc) 17.2 kB
'use strict'; var chalk = require('chalk'), fs = require('fs'), _s = require('underscore.string'), areJHipsterEntitiesEqual = require('./helpers/object_helper').areJHipsterEntitiesEqual, types_helper = require('./types/types_helper'), association_helper = require('./helpers/association_helper'), cardinalities = require('./cardinalities'), formatComment = require('./helpers/comment_helper'), NullPointerException = require('./exceptions/null_pointer_exception'), NoSQLModelingException = require('./exceptions/no_sql_modeling_exception'); var EntitiesCreator = module.exports = function(parsedData, databaseTypes, listDTO, listPagination, listService) { if (!parsedData) { throw new NullPointerException('There is no parsed data.'); } this.USER = 'User'; this.entitiesToSuppress = []; //the option list this.listDTO = listDTO; this.listPagination = listPagination; this.listService = listService; this.databaseTypes = databaseTypes; this.parsedData = parsedData; this.checkNoSQLModeling(); this.entities = {}; // cache for the the entities read on the disk this.onDiskEntities = {}; }; EntitiesCreator.prototype.getEntities = function() { return this.entities; }; EntitiesCreator.prototype.createEntities = function() { this.initializeEntities(); Object.keys(this.parsedData.classes).forEach(function(classId) { /* * If the user adds a 'User' entity we consider it as the already * created JHipster User entity and none of its fields and ownerside * relationships will be considered. */ if (this.parsedData.getClass(classId).name.toLowerCase() === this.USER.toLowerCase()) { console.warn( chalk.yellow( "Warning: An Entity called 'User' was defined: 'User' is an" + ' entity created by default by JHipster. All relationships toward' + ' it will be kept but all attributes and relationships from it' + ' will be disregarded.')); this.entitiesToSuppress.push(classId); } this.setFieldsOfEntity(classId); this.setRelationshipOfEntity(classId); },this); this.entitiesToSuppress.forEach(function(entity) { delete this.entities[entity]; }, this); }; /** * Initialize all Entities with default values */ EntitiesCreator.prototype.initializeEntities = function() { this.onDiskEntities = this.readJSON(Object.keys(this.parsedData.classes)); Object.keys(this.parsedData.classes).forEach(function(classId, index) { var initializedEntity = { relationships: [], fields: [], changelogDate: this.getChangelogDate(classId, index), dto: this.parsedData.getClass(classId).dto, pagination: this.parsedData.getClass(classId).pagination, service: this.parsedData.getClass(classId).service, javadoc: formatComment(this.parsedData.getClass(classId).comment), entityTableName: _s.underscored(this.parsedData.getClass(classId).tableName) }; initializedEntity = this.setDTO( initializedEntity, this.parsedData.getClass(classId).name); initializedEntity = this.setPagination( initializedEntity, this.parsedData.getClass(classId).name); initializedEntity = this.setService( initializedEntity, this.parsedData.getClass(classId).name); this.entities[classId] = initializedEntity; }, this); }; /** * If the entity already have a json file we get the changelogDate in it * else we create the changelogDate with liquibase date format * @param{String} classId the id of the class to set the changelogDate property * @param{Integer} increment the optional increment in the timestamp? * @return the date on liquibase format */ EntitiesCreator.prototype.getChangelogDate = function(classId, increment) { if (this.onDiskEntities[classId]) { return this.onDiskEntities[classId].changelogDate; } return dateFormatForLiquibase(increment); }; /** * fill the fields of the current entity * param{String} classId the id of the current entity */ EntitiesCreator.prototype.setFieldsOfEntity = function(classId) { this.parsedData.classes[classId].fields.forEach(function(fieldId) { var fieldData = { fieldId: this.entities[classId].fields.length + 1, fieldName: _s.camelize(this.parsedData.getField(fieldId).name), javadoc: formatComment(this.parsedData.getField(fieldId).comment) }; if (this.parsedData.types[this.parsedData.getField(fieldId).type]) { fieldData.fieldType = this.parsedData.getType(this.parsedData.getField(fieldId).type).name; } else if (this.parsedData.getEnum(this.parsedData.getField(fieldId).type)) { fieldData.fieldType = this.parsedData.getEnum(this.parsedData.getField(fieldId).type).name; fieldData.fieldValues = this.parsedData.getEnum(this.parsedData.getField(fieldId).type).values.join(','); } if (fieldData.fieldType === 'ImageBlob') { fieldData.fieldType = 'byte[]'; fieldData.fieldTypeBlobContent = 'image'; } else if (fieldData.fieldType === 'Blob' || fieldData.fieldType === 'AnyBlob') { fieldData.fieldType = 'byte[]'; fieldData.fieldTypeBlobContent = 'any'; } this.setValidationsOfField(fieldData, fieldId); this.entities[classId].fields.push(fieldData); }, this); }; /** * Gets a fields and adds the related validations. * @param {Object} field the field. * @param {String} fieldId the field's id. */ EntitiesCreator.prototype.setValidationsOfField = function(field, fieldId) { if (this.parsedData.getField(fieldId).validations.length === 0) { return; } field.fieldValidateRules = []; this.parsedData.getField(fieldId).validations.forEach(function(validationId) { var validation = this.parsedData.getValidation(validationId); field.fieldValidateRules.push(validation.name); if(validation.name !== 'required') { field['fieldValidateRules' + _s.capitalize(validation.name)] = validation.value; } }, this); }; function getRelatedAssociations(classId, associationIds, associations) { var relationships = { from: [], to: [] }; associationIds.forEach(function(associationId) { var association = associations[associationId]; if (association.from === classId) { relationships.from.push(associationId); } if (association.to === classId && association.injectedFieldInTo) { relationships.to.push(associationId); } }, this); return relationships; } /** * Parses the string "<relationshipName>(<otherEntityField>)" * @param{String} field * @return{Object} where 'relationshipName' is the relationship name and * 'otherEntityField' is the other entity field name */ function extractField(field) { var splitField = { otherEntityField: 'id', // id by default relationshipName: '' }; if (field) { var chunks = field.replace('(', '/').replace(')', '').split('/'); splitField.relationshipName = chunks[0]; if (chunks.length > 1) { splitField.otherEntityField = chunks[1]; } } return splitField; } EntitiesCreator.prototype.setRelationshipOfEntity = function(classId) { var associations = getRelatedAssociations( classId, Object.keys(this.parsedData.associations), this.parsedData.associations); associations.from.forEach(function(associationId) { var otherSplitField; var splitField; var association = this.parsedData.getAssociation(associationId); association_helper.checkValidityOfAssociation( association, this.parsedData.getClass(association.from).name, this.parsedData.getClass(association.to).name); var relationship = { relationshipId: this.entities[classId].relationships.length + 1, relationshipType: association.type }; if (association.type === cardinalities.ONE_TO_ONE) { splitField = extractField(association.injectedFieldInFrom); relationship.relationshipName = _s.camelize(splitField.relationshipName); relationship.otherEntityName = _s.decapitalize(_s.camelize(this.parsedData.getClass(association.to).name)); relationship.otherEntityField = _s.decapitalize(splitField.otherEntityField); relationship.ownerSide = true; relationship.otherEntityRelationshipName = _s.decapitalize(association.injectedFieldInTo || this.parsedData.getClass(association.from).name); } else if (association.type === cardinalities.ONE_TO_MANY) { splitField = extractField(association.injectedFieldInFrom); otherSplitField = extractField(association.injectedFieldInTo); relationship.relationshipName = _s.decapitalize(_s.camelize(splitField.relationshipName || this.parsedData.getClass(association.to).name)); relationship.otherEntityName = _s.decapitalize(_s.camelize(this.parsedData.getClass(association.to).name)); relationship.otherEntityRelationshipName = _s.decapitalize(otherSplitField.relationshipName); if (!association.injectedFieldInTo) { relationship.otherEntityRelationshipName = _s.decapitalize(this.parsedData.getClass(association.from).name); otherSplitField = extractField(association.injectedFieldInTo); var otherSideRelationship = { relationshipId: this.entities[association.to].relationships.length + 1, relationshipName: _s.camelize(_s.decapitalize(this.parsedData.getClass(association.from).name)), otherEntityName: _s.decapitalize(_s.camelize(this.parsedData.getClass(association.from).name)), relationshipType: cardinalities.MANY_TO_ONE, otherEntityField: _s.decapitalize(otherSplitField.otherEntityField) }; association.type = cardinalities.MANY_TO_ONE; this.entities[association.to].relationships.push(otherSideRelationship); } } else if (association.type === cardinalities.MANY_TO_ONE && association.injectedFieldInFrom) { splitField = extractField(association.injectedFieldInFrom); relationship.relationshipName = _s.camelize(splitField.relationshipName); relationship.otherEntityName = _s.decapitalize(_s.camelize(this.parsedData.getClass(association.to).name)); relationship.otherEntityField = _s.decapitalize(splitField.otherEntityField); } else if (association.type === cardinalities.MANY_TO_MANY) { splitField = extractField(association.injectedFieldInFrom); relationship.relationshipName = _s.camelize(splitField.relationshipName); relationship.otherEntityName = _s.decapitalize(_s.camelize(this.parsedData.getClass(association.to).name)); relationship.otherEntityField = _s.decapitalize(splitField.otherEntityField); relationship.ownerSide = true; } this.entities[classId].relationships.push(relationship); }, this); associations.to.forEach(function(associationId) { var splitField; var otherSplitField; var association = this.parsedData.getAssociation(associationId); var relationship = { relationshipId: this.entities[classId].relationships.length + 1, relationshipType: (association.type === cardinalities.ONE_TO_MANY ? cardinalities.MANY_TO_ONE : association.type) }; if (association.type === cardinalities.ONE_TO_ONE) { splitField = extractField(association.injectedFieldInTo); otherSplitField = extractField(association.injectedFieldInFrom); relationship.relationshipName = _s.camelize(splitField.relationshipName); relationship.otherEntityName = _s.decapitalize(_s.camelize(this.parsedData.getClass(association.from).name)); relationship.ownerSide = false; relationship.otherEntityRelationshipName = _s.decapitalize(otherSplitField.relationshipName); } else if (association.type === cardinalities.ONE_TO_MANY) { association.injectedFieldInTo = association.injectedFieldInTo || _s.decapitalize(association.from); splitField = extractField(association.injectedFieldInTo); relationship.relationshipName = _s.decapitalize(_s.camelize(splitField.relationshipName || this.parsedData.getClass(association.from).name)); relationship.otherEntityName =_s.decapitalize(_s.camelize(this.parsedData.getClass(association.from).name)); relationship.otherEntityField = _s.decapitalize(splitField.otherEntityField); } else if (association.type === cardinalities.MANY_TO_ONE && association.injectedFieldInTo) { splitField = extractField(association.injectedFieldInTo); relationship.relationshipName = _s.camelize(splitField.relationshipName); relationship.otherEntityName = _s.decapitalize(_s.camelize(this.parsedData.getClass(association.from).name)); relationship.otherEntityField = _s.decapitalize(splitField.otherEntityField); } else if (association.type === cardinalities.MANY_TO_MANY) { splitField = extractField(association.injectedFieldInTo); relationship.relationshipName= _s.camelize(splitField.relationshipName); relationship.otherEntityName = _s.decapitalize(_s.camelize(this.parsedData.getClass(association.from).name)); relationship.ownerSide = false; relationship.otherEntityRelationshipName = _s.decapitalize(extractField(association.injectedFieldInFrom).relationshipName); } this.entities[classId].relationships.push(relationship); }, this); }; /** * For each class in classesToRead, reads the corresponding JSON in .jhipster. * @param{array} classesToRead all the classes we want to read. * @return {object} the read entities. */ EntitiesCreator.prototype.readJSON = function(classesToRead) { var entitiesRead = {}; classesToRead.forEach(function(classToRead) { var file = '.jhipster/' + this.parsedData.getClass(classToRead).name + '.json'; if (this.onDiskEntities[classToRead]) { entitiesRead[classToRead] = this.onDiskEntities[classToRead]; } else if(fs.existsSync(file)) { entitiesRead[classToRead] = JSON.parse(fs.readFileSync(file, 'utf8')); } }, this); return entitiesRead; }; /** * @param{Array} classList the classes we want to create a JSON for * Write a JSON file for each entity in classList in the .jhipster folder */ EntitiesCreator.prototype.writeJSON = function(classList) { if (!fs.existsSync('.jhipster')) { fs.mkdirSync('.jhipster'); } for (var k in this.entities) { if (this.entities.hasOwnProperty(k) && classList.indexOf(k) !== -1) { var file = '.jhipster/' + this.parsedData.getClass(k).name + '.json'; fs.writeFileSync(file, JSON.stringify(this.entities[k], null, ' ')); } } }; /** * Removes all unchanged entities. * @param {Array} entities all the entities to filter. * @returns {Array} the changed entities. */ EntitiesCreator.prototype.filterOutUnchangedEntities = function(entities) { var onDiskEntities = this.readJSON(entities); return entities.filter(function(id) { var currEntity = onDiskEntities[id]; var newEntity = this.entities[id]; if (!currEntity) { return true; } return !areJHipsterEntitiesEqual(currEntity, newEntity); }, this); }; /* * Throws an error if the user declared relationships when using a NoSQL database */ EntitiesCreator.prototype.checkNoSQLModeling = function() { if(types_helper.isNoSQL(this.databaseTypes) && Object.keys(this.parsedData.associations).length !== 0) { throw new NoSQLModelingException( 'While using a NoSQL database do not create relationships between entities.'); } }; /* * @param {Object} entity the initialized entity * @param {Object} entityName the name of the entity * @return {Object} the entity with the 'dto' property set according to listDTO. */ EntitiesCreator.prototype.setDTO = function(entity, entityName) { if (this.listDTO.indexOf(entityName) !== -1) { entity.dto = 'mapstruct'; } return entity; }; /* * @param {Object} entity the initialized entity * @param {Object} entityName the name of the entity * @return {Object} the entity with the 'pagination' property set according * to listPagination. */ EntitiesCreator.prototype.setPagination = function(entity, entityName) { if (this.listPagination.hasOwnProperty(entityName)) { entity.pagination = this.listPagination[entityName]; } return entity; }; EntitiesCreator.prototype.setService = function(entity, entityName) { if (this.listService.hasOwnProperty(entityName)) { entity.service = this.listService[entityName]; } return entity; }; function dateFormatForLiquibase(increment) { var now = new Date(); var now_utc = new Date(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate(), now.getUTCHours(), now.getUTCMinutes(), now.getUTCSeconds()); var year = '' + now_utc.getFullYear(); var month = '' + (now_utc.getMonth() + 1); if (month.length === 1) { month = '0' + month; } var day = '' + now_utc.getDate(); if (day.length === 1) { day = '0' + day; } var hour = '' + now_utc.getHours(); if (hour.length === 1) { hour = '0' + hour; } var minute = '' + now_utc.getMinutes(); if (minute.length === 1) { minute = '0' + minute; } var second = '' + (now_utc.getSeconds() + increment) % 60; if (second.length === 1) { second = '0' + second; } return year + '' + month + '' + day + '' + hour + '' + minute + '' + second; }