UNPKG

webgme-dss

Version:

Design Studio for Dynamic Systems with Modelica as backend

363 lines (316 loc) 15.3 kB
/*globals define*/ /*eslint-env node, browser*/ /** * Generated by PluginGenerator 2.16.0 from webgme on Wed Feb 07 2018 14:29:28 GMT-0600 (Central Standard Time). * A plugin that inherits from the PluginBase. To see source code documentation about available * properties and methods visit %host%/docs/source/PluginBase.html. */ define([ 'plugin/PluginConfig', 'text!./metadata.json', 'plugin/PluginBase', 'common/util/random', 'q' ], function (PluginConfig, pluginMetadata, PluginBase, RANDOM, Q) { 'use strict'; pluginMetadata = JSON.parse(pluginMetadata); /** * Initializes a new instance of ModelicaDiff. * @class * @augments {PluginBase} * @classdesc This class represents the plugin ModelicaDiff. * @constructor */ var ModelicaDiff = function () { // Call base class' constructor. PluginBase.call(this); this.pluginMetadata = pluginMetadata; }; /** * Metadata associated with the plugin. Contains id, name, version, description, icon, configStructue etc. * This is also available at the instance at this.pluginMetadata. * @type {object} */ ModelicaDiff.metadata = pluginMetadata; // Prototypical inheritance from PluginBase. ModelicaDiff.prototype = Object.create(PluginBase.prototype); ModelicaDiff.prototype.constructor = ModelicaDiff; ModelicaDiff.prototype._getPortMap = function (core, node) { var metaNodes = core.getAllMetaNodes(node, true), metaNode = core.getMetaType(node), portPaths = core.getChildrenPaths(metaNode), paths2names = {}; portPaths.forEach(function (path) { paths2names[path] = core.getAttribute(metaNodes[path], 'name'); }); return paths2names; }; ModelicaDiff.prototype.gatherModelChanges = function (core, oldRoot, newRoot, diff) { var self = this, deferred = Q.defer(), oldRelids, newRelids, changes = {}; Q.all([core.loadByPath(oldRoot, '/Z'), core.loadByPath(newRoot, '/Z')]) .then(function (models) { var i, promises = []; oldRelids = core.getChildrenRelids(models[0]); newRelids = core.getChildrenRelids(models[1]); i = oldRelids.length; while (i--) { if (diff[oldRelids[i]] === undefined) { oldRelids.splice(i, 1); } } i = newRelids.length; while (i--) { if (diff[newRelids[i]] === undefined) { newRelids.splice(i, 1); } } for (i = 0; i < oldRelids.length; i += 1) { promises.push(core.loadByPath(models[0], '/' + oldRelids[i])); } for (i = 0; i < newRelids.length; i += 1) { promises.push(core.loadByPath(models[1], '/' + newRelids[i])); } return Q.all(promises); }) .then(function (children) { var i, childDiff, names, key, oldName2id = {}, newName2id = {}, oldNodes = {}, newNodes = {}, oldConnections = {}, newConnections = {}; for (i = 0; i < oldRelids.length; i += 1) { if (core.isConnection[children[i]]) { key = oldConnections[core.getPointerPath(children[i], 'src')]; oldConnections[key] = oldConnections[key] || []; oldConnections[key].push(core.getPointerPath(children[i], 'dst')); } else { key = core.getAttribute(children[i], 'name'); oldName2id[key] = core.getPath(children[i]); oldNodes[key] = children[i]; } } for (i; i < children.length; i += 1) { if (core.isConnection[children[i]]) { key = newConnections[core.getPointerPath(children[i], 'src')]; newConnections[key] = newConnections[key] || []; newConnections[key].push(core.getPointerPath(children[i], 'dst')); } else { key = core.getAttribute(children[i], 'name'); newName2id[key] = core.getPath(children[i]); newNodes[key] = children[i]; } } // new elements and updates for (i in newNodes) { changes[i] = []; if (oldNodes.hasOwnProperty(i) === false) { changes[i] = ['Component have been introduced to the model.']; } else { // we need to check the diff for guidance childDiff = diff[core.getRelid(oldNodes[i])]; if (childDiff.removed === undefined && (childDiff.attr === undefined || !childDiff.attr.hasOwnProperty('name'))) { // only attribute and registry changes for (names in childDiff.attr || {}) { changes[i].push('Attribute [' + names + '] changed {' + core.getAttribute(oldNodes[i], names) + ' -> ' + core.getAttribute(newNodes[i], names) + '}.'); } // only the position can change if there is registry change if (childDiff.reg && childDiff.reg.position) { names = core.getRegistry(oldNodes[i], 'position'); key = core.getRegistry(newNodes[i], 'position'); changes[i].push('Onscreen position changed {x: ' + names.x + ' -> ' + key.x + ' , y: ' + names.y + ' -> ' + key.y + '}.'); } } else { console.log(JSON.stringify(childDiff)); // same name exists in both versions under different nodes, so we assume the are the same changes[i].push(' Component have been re-created.'); names = core.getValidAttributeNames(oldNodes[i]); for (key = 0; key < names.length; key += 1) { if (core.getAttribute(oldNodes[i], names[key]) !== core.getAttribute(oldNodes[i], names[key])) { changes[i].push('Attribute [' + names[key] + '] changed {' + core.getAttribute(oldNodes[i], names[key]) + ' -> ' + core.getAttribute(newNodes[i], names[key]) + '}.'); } } names = core.getRegistry(oldNodes[i], 'position'); key = core.getRegistry(newNodes[i], 'position'); if (names.x !== key.x || names.y !== key.y) { changes[i].push('Onscreen position changed {x: ' + names.x + ' -> ' + key.x + ' , y: ' + names.y + ' -> ' + key.y + '.'); } } } // now we need to check the connection changes // TODO - how to do it??? /*var portInfo = self._getPortMap(core, newNodes[i]), j, portPath, oldDsts, newDsts; for (portPath in portInfo) { if (oldConnections[portPath]) { oldDsts = {}; newDsts = {}; for(j=0;j<oldConnections[portPath].length;j+=1){ oldDsts[portPath] = true; //TODO should be the name of the port... } } }*/ } // removals for (i in oldNodes) { if (newNodes.hasOwnProperty(i) === false) { changes[i] = ['Component have been removed from the model.']; } } if (Object.keys(changes).length === 0) { changes = null; } deferred.resolve(changes); }) .catch(deferred.reject); return deferred.promise; }; ModelicaDiff.prototype.gatherDomainChanges = function (core, oldRoot, newRoot, diff) { let deferred = Q.defer(), oldDomains = {}, newDomains = {}, relids, i, promises = [], oldSize, changes = []; relids = core.getChildrenRelids(oldRoot); oldSize = 0; for (i = 0; i < relids.length; i += 1) { if (diff.hasOwnProperty(relids[i])) { oldSize += 1; promises.push(core.loadByPath(oldRoot, '/' + relids[i])); } } relids = core.getChildrenRelids(newRoot); for (i = 0; i < relids.length; i += 1) { if (diff.hasOwnProperty(relids[i])) { promises.push(core.loadByPath(newRoot, '/' + relids[i])); } } Q.all(promises) .then((children) => { for (i = 0; i < oldSize; i += 1) { oldDomains[core.getAttribute(children[i], 'name')] = true; } for (i; i < children.length; i += 1) { newDomains[core.getAttribute(children[i], 'name')] = true; } // added for (i in newDomains) { if (!oldDomains.hasOwnProperty(i)) { changes.push('Domain "' + i + '" have been added to the project.'); } } // removed for (i in oldDomains) { if (!newDomains.hasOwnProperty(i)) { changes.push('Domain "' + i + '" have been removed from the project.'); } } deferred.resolve(changes.length === 0 ? null : changes); }) .catch(deferred.reject); return deferred.promise; }; ModelicaDiff.prototype.gatherSimulationChanges = function (core, oldRoot, newRoot, diff) { let deferred = Q.defer(), oldDomains = {}, newDomains = {}, relids, i, promises = [], oldSize, changes = []; Q.all([ core.loadByPath(oldRoot, '/8'), core.loadByPath(newRoot, '/8') ]) .then((simulationFolders) => { let relids, i, promises = []; oldSize = 0; relids = core.getChildrenRelids(simulationFolders[0]); for (i = 0; i < relids.length; i += 1) { if (diff.hasOwnProperty(relids[i]) && diff[relids[i]].removed === true) { oldSize += 1; promises.push(core.loadByPath(simulationFolders[0], '/' + relids[i])); } } relids = core.getChildrenRelids(simulationFolders[1]); for (i = 0; i < relids.length; i += 1) { if (diff.hasOwnProperty(relids[i]) && diff[relids[i]].removed === false) { promises.push(core.loadByPath(simulationFolders[1], '/' + relids[i])); } } return Q.all(promises); }) .then((simulations) => { let i, oldSimulations, newSimulations, changes = []; for (i = 0; i < oldSize; i += 1) { changes.push('Simulation result "' + core.getAttribute(simulations[i], 'name') + '" has been dropped.'); } for (i; i < simulations.length; i += 1) { changes.push('Simulation result "' + core.getAttribute(simulations[i], 'name') + '" has been created.'); } deferred.resolve(changes.length === 0 ? null : changes); }) .catch(deferred.reject); return deferred.promise; }; /** * Main function for the plugin to execute. This will perform the execution. * Notes: * - Always log with the provided logger.[error,warning,info,debug]. * - Do NOT put any user interaction logic UI, etc. inside this method. * - callback always has to be called even if error happened. * * @param {function(string, plugin.PluginResult)} callback - the result callback */ ModelicaDiff.prototype.main = function (callback) { // Use self to access core, project, result, logger etc from PluginBase. // These are all instantiated at this point. var self = this, config = self.getCurrentConfig(), core = self.core, currentRoot = self.activeNode, changes = {model: null, domain: null, simulation: null}, oldRoot, diff; core.loadRoot(config.oldRootHash) .then((oldRoot_) => { oldRoot = oldRoot_; return core.generateTreeDiff(oldRoot, currentRoot); }) .then((diff_) => { diff = diff_; return self.gatherModelChanges(core, oldRoot, currentRoot, diff.Z || {}); }) .then((modelChanges) => { changes.model = modelChanges; return self.gatherDomainChanges(core, oldRoot, currentRoot, diff || {}); }) .then((domainChanges) => { changes.domain = domainChanges; return self.gatherSimulationChanges(core, oldRoot, currentRoot, diff['8'] || {}); }) .then((simulationChanges) => { changes.simulation = simulationChanges; self.result.setSuccess(true); console.log(changes); self.createMessage(currentRoot, JSON.stringify(changes), 'info'); callback(null, self.result); }) .catch(function (err) { self.result.setSuccess(false); callback(err, self.result); }); }; return ModelicaDiff; });