UNPKG

webgme-dss

Version:

Design Studio for Dynamic Systems with Modelica as backend

261 lines (223 loc) 10.1 kB
/*globals define*/ /*eslint-env node, browser*/ /** * Generated by PluginGenerator 2.16.0 from webgme on Thu Feb 01 2018 16:33:12 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. */ (function (factory) { if (typeof define === 'function' && define.amd) { define([ 'plugin/PluginConfig', 'text!./metadata.json', 'plugin/PluginBase', ], factory); } else if (typeof module === 'object' && module.exports) { module.exports = factory( require('webgme-engine/src/plugin/PluginConfig'), require('./metadata.json'), require('webgme-engine/src/plugin/PluginBase'), ); } }(function (PluginConfig, pluginMetadata, PluginBase) { pluginMetadata = typeof pluginMetadata === 'string' ? JSON.parse(pluginMetadata) : pluginMetadata; /** * Initializes a new instance of ModelicaCodeGenerator. * @class * @augments {PluginBase} * @classdesc This class represents the plugin ModelicaCodeGenerator. * @constructor */ function ModelicaCodeGenerator() { // 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} */ ModelicaCodeGenerator.metadata = pluginMetadata; // Prototypical inheritance from PluginBase. ModelicaCodeGenerator.prototype = Object.create(PluginBase.prototype); ModelicaCodeGenerator.prototype.constructor = ModelicaCodeGenerator; /** * 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 */ ModelicaCodeGenerator.prototype.main = function main(callback) { const {logger} = this; function getMoFileContent(modelJson) { // TODO: This string concatenation should be changed (it's from the MIC class demo).. let moFile = 'model ' + modelJson.name; // 11) Using the modelJson data that we built up we extract the data for the modelica // code and build up the code. modelJson.components .sort((a, b) => { if (a.URI > b.URI) { return 1; } else if (a.URI < b.URI) { return -1; } else if (a.name > b.name) { return 1; } else if (a.name < b.name) { return -1; } return 0; }) .forEach((data) => { const params = Object.keys(data.parameters); moFile += '\n ' + data.URI + ' ' + data.name; if (params.length > 0) { moFile += '('; params.map((p, idx) => { moFile += `${p} = ${data.parameters[p]}, `; if (idx === params.length - 1) { if (data.modifiers) { moFile += data.modifiers; } else { moFile = moFile.slice(0, -2); } } }); moFile += ')'; } else if (data.modifiers) { moFile += `(${data.modifiers})`; } moFile += ';'; }); moFile += '\nequation'; modelJson.connections .sort((a, b) => { if (a.src > b.src) { return 1; } else if (a.src < b.src) { return -1; } else if (a.dst > b.dst) { return 1; } else if (a.dst < b.dst) { return -1; } return 0; }) .forEach((data) => { moFile += '\n connect(' + data.src + ', ' + data.dst + ');'; }); moFile += '\nend ' + modelJson.name + ';'; logger.debug(moFile); return moFile; } // 1) Retrieve an object will all nodes in the subtree of activeNode this.loadNodeMap(this.activeNode) .then((nodes) => { const modelJson = this.extractModelData(nodes); // 10) We turn the data-structure into a string (indentation 2) and log it logger.debug('modelJson', JSON.stringify(modelJson, null, 2)); const moFile = getMoFileContent(modelJson); this.moFile = moFile; logger.debug('moFile', moFile); // 12) Add the modelic file content as a file on the blobstorage. return this.blobClient.putFile(`${modelJson.name}.mo`, moFile); }) .then((metadataHash) => { logger.debug(metadataHash); // 13) Link the uploaded file (using the hash) from the plugin result. this.result.addArtifact(metadataHash); this.result.setSuccess(true); callback(null, this.result); }) .catch((err) => { logger.error(err.stack); callback(err, this.result); }); }; ModelicaCodeGenerator.prototype.extractModelData = function extractModelData(nodes) { const { core, META, activeNode, logger, } = this; const modelJson = { name: '', components: [], connections: [], }; function atComponent(node) { const componentData = { URI: '', name: '', parameters: {}, modifiers: '', }; // 5) Extract the data we need from the components. componentData.URI = core.getAttribute(node, 'ModelicaURI'); componentData.name = core.getAttribute(node, 'name'); core.getAttributeNames(node).forEach((attrName) => { if (attrName !== 'name' && !core.getAttributeMeta(node, attrName).readonly) { if (attrName === 'modifiers') { componentData.modifiers = core.getAttribute(node, attrName) || ''; } else { componentData.parameters[attrName] = core.getAttribute(node, attrName); } } }); // 6) Push the data to the components array. modelJson.components.push(componentData); } function atConnection(node) { const connData = { src: '', dst: '', }; // 7) Extract the data we need from connections. const srcPath = core.getPointerPath(node, 'src'); const dstPath = core.getPointerPath(node, 'dst'); // 8) Only if both src and dst exist will the connection be accounted for if (srcPath && dstPath) { // (since connData is a referenced data-type we can push here and modify below) modelJson.connections.push(connData); const srcNode = nodes[srcPath]; const dstNode = nodes[dstPath]; // 9) Since the ports are contained in components we extract the parents in // order to get the full modelica path to the port-instance. const srcParent = core.getParent(srcNode); const dstParent = core.getParent(dstNode); connData.src = core.getAttribute(srcParent, 'name') + '.' + core.getAttribute(srcNode, 'name'); connData.dst = core.getAttribute(dstParent, 'name') + '.' + core.getAttribute(dstNode, 'name'); } } for (let path in nodes) { logger.debug(core.getAttribute(nodes[path], 'name')); } modelJson.name = core.getAttribute(activeNode, 'name'); // 2) Get all the children paths of the active node // (these are the immediated children) const childrenPaths = core.getChildrenPaths(activeNode); logger.debug('Paths', childrenPaths); let childNode; // 3) Iterate of the paths and retrieve the node using the node // map from 1) for (let i = 0; i < childrenPaths.length; i += 1) { childNode = nodes[childrenPaths[i]]; // 4) Check the meta-type of the child-node and take action based on type. if (core.isTypeOf(childNode, META.ComponentBase)) { logger.debug('Component:', core.getAttribute(childNode, 'name')); atComponent(childNode); } else if (core.isTypeOf(childNode, META.ConnectionBase)) { logger.debug('Connection:', core.getAttribute(childNode, 'name')); atConnection(childNode); } } return modelJson; }; return ModelicaCodeGenerator; }));