UNPKG

webgme-bip

Version:

Design studio for component-based modeling with BIP.

346 lines (308 loc) 14.1 kB
/*globals define*/ /*jshint node:true, browser:true*/ /** * Generated by PluginGenerator 1.7.0 from webgme on Wed Mar 08 2017 15:24:49 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', 'q', 'common/util/ejs', 'bipsrc/util/utils', 'bipsrc/templates/ejsCache', 'bipsrc/parsers/javaExtra', 'bipsrc/bower_components/pegjs/peg-0.10.0' ], function (PluginConfig, pluginMetadata, PluginBase, Q, ejs, utils, ejsCache, javaParser, peg) { 'use strict'; pluginMetadata = JSON.parse(pluginMetadata); /** * Initializes a new instance of ComponentTypeGenerator. * @class * @augments {PluginBase} * @classdesc This class represents the plugin ComponentTypeGenerator. * @constructor */ var BehaviorSpecGenerator = 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} */ BehaviorSpecGenerator.metadata = pluginMetadata; // Prototypical inheritance from PluginBase. BehaviorSpecGenerator.prototype = Object.create(PluginBase.prototype); BehaviorSpecGenerator.prototype.constructor = BehaviorSpecGenerator; /** * 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 */ BehaviorSpecGenerator.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, nodes, artifact; self.loadNodeMap(self.activeNode) .then(function (nodes_) { nodes = nodes_; return BehaviorSpecGenerator.getGeneratedFiles(self, nodes, self.activeNode); }) .then(function (result) { if (result.violations.length > 0) { result.violations.forEach(function (violation) { self.createMessage(violation.node, violation.message, 'error'); }); throw new Error('Model has ' + result.violations.length + ' violation(s). ' + 'See messages for details.'); } artifact = self.blobClient.createArtifact('BehaviorSpecifications'); return artifact.addFiles(result.files); }) .then(function (fileHashes) { fileHashes.forEach(function (fileHash) { self.result.addArtifact(fileHash); }); return artifact.save(); }) .then(function (artifactHash) { self.result.addArtifact(artifactHash); self.result.setSuccess(true); callback(null, self.result); }) .catch(function (err) { self.logger.error(err.stack); // Result success is false at invocation. callback(err, self.result); }); }; /** * * @param {PluginBase} self - An initialized and configured plugin. * @param {Object<string, Object>} nodes - all nodes loaded from the projectNode. * @param {object} activeNode - the projectNode. * * @returns {Promise} resolves with {files: Object<string, string>, violations: Objects[]} */ BehaviorSpecGenerator.getGeneratedFiles = function (self, nodes, activeNode, callback) { var componentTypePaths = BehaviorSpecGenerator.prototype.getComponentTypePaths.call(self, nodes), violations = BehaviorSpecGenerator.prototype.getViolations.call(self, componentTypePaths, nodes), fileNames = [], promises = [], fileName, type; self.logger.debug('number of components', componentTypePaths.length); for (type of componentTypePaths) { fileName = self.core.getAttribute(nodes[type], 'name') + '.java'; fileNames.push(fileName); self.logger.debug('filename ' + fileName); promises.push(BehaviorSpecGenerator.prototype.getComponentTypeFile.call(self, nodes[type], violations)); } return Q.all(promises) .then(function (result) { var i, files = {}; for (i = 0; i < fileNames.length; i += 1) { files[fileNames[i]] = result[i]; } return { files: files, violations: violations }; }) .nodeify(callback); }; BehaviorSpecGenerator.prototype.getGuardExpression = function (componentModel) { var guardNames = [], i, guardExpressionParser; for (i = 0; i < componentModel.guards.length; i += 1) { guardNames.push(componentModel.guards[i].name); } if (guardNames.length > 0) { guardExpressionParser = peg.generate( ejs.render(ejsCache.guardExpression, {guardNames: guardNames}) ); } return guardExpressionParser; }; BehaviorSpecGenerator.prototype.getComponentTypePaths = function (nodes) { var self = this, path, node, componentTypes = []; for (path in nodes) { node = nodes[path]; //TODO: Update for hierarchical components if (self.isMetaTypeOf(node, self.META.ComponentType) && (!self.isMetaTypeOf(self.core.getParent(node), self.META.ArchitectureStyle)) && (!self.isMetaTypeOf(self.core.getParent(node), self.META.ComponentTypesLibrary))) { componentTypes.push(path); } } return componentTypes; }; BehaviorSpecGenerator.prototype.getComponentTypeFile = function (componentTypeNode, violations, callback) { var self = this, fileContent, guardExpressionParser, i; return utils.getModelOfComponentType(self.core, componentTypeNode) .then(function (componentModel) { fileContent = ejs.render(ejsCache.componentType.complete, componentModel); var parseResult = javaParser.checkWholeFile(fileContent); if (parseResult) { self.logger.debug(parseResult.line); self.logger.debug(parseResult.message); parseResult.node = componentTypeNode; violations.push(parseResult); } guardExpressionParser = BehaviorSpecGenerator.prototype.getGuardExpression.call(self, componentModel); for (i = 0; i < componentModel.transitions.length; i += 1) { if (componentModel.transitions[i].guard.length > 0) { try { parseResult = guardExpressionParser.parse(componentModel.transitions[i].guard); } catch (e) { violations.push({ message: 'Guard expression [' + componentModel.transitions[i].guard + '] is not a logical expression that has only defined guard names as symbols. Please update. The allowed symbols of logical operators are: & for conjunnction, | for disjunction and ! for negation.', node: componentTypeNode }); } } } return fileContent; }) .nodeify(callback); }; BehaviorSpecGenerator.prototype.getViolations = function (componentTypes, nodes) { var componentTypeNames = {}, name, type, node, child, childPath, childName, self = this, noInitialState, nameAndViolations = { violations: [], totalStateNames: {}, transitionNames: {}, guardNames: {} }; for (type of componentTypes) { nameAndViolations.guardNames = {}; nameAndViolations.totalStateNames = {}; nameAndViolations.transitionNames = {}; noInitialState = true; node = nodes[type]; name = self.core.getAttribute(node, 'name'); if (componentTypeNames.hasOwnProperty(name)) { nameAndViolations.violations.push({ node: node, message: 'Name [' + name + '] of component type [' + type + '] is not unique. Please rename. ' + 'Component types must have unique names. ' }); } componentTypeNames[name] = self.core.getPath(node); for (childPath of self.core.getChildrenPaths(node)) { child = nodes[childPath]; childName = self.core.getAttribute(child, 'name'); if ((self.isMetaTypeOf(child, self.META.InitialState))) { noInitialState = false; } nameAndViolations = BehaviorSpecGenerator.prototype.hasChildViolations.call(self, child, childName, nameAndViolations); } if (noInitialState) { nameAndViolations.violations.push({ node: node, message: 'Component type [' + name + '] does not have an initial state. ' + 'Please define an initial state.' }); } } return nameAndViolations.violations; }; BehaviorSpecGenerator.prototype.hasChildViolations = function (child, childName, nameAndViolations) { var self = this; if ((self.isMetaTypeOf(child, self.META.State)) || (self.isMetaTypeOf(child, self.META.InitialState))) { if (nameAndViolations.totalStateNames.hasOwnProperty(childName)) { nameAndViolations.violations.push({ node: child, message: 'Name [' + childName + '] of state [' + child + '] is not unique. ' + 'Please rename. States that belong to the same component type must have unique names.' }); } nameAndViolations.totalStateNames[childName] = self.core.getPath(child); } if (self.isMetaTypeOf(child, self.META.EnforceableTransition) || self.isMetaTypeOf(child, self.META.SpontaneousTransition) || self.isMetaTypeOf(child, self.META.InternalTransition)) { if (this.core.getPointerPath(child, 'dst') === null) { nameAndViolations.violations.push({ node: child, message: 'Transition [' + childName + '] with no destination encountered. ' + 'Please connect or remove it.' }); } if (this.core.getPointerPath(child, 'src') === null) { nameAndViolations.violations.push({ node: child, message: 'Transition [' + childName + '] with no source encountered. Please connect or remove it.' }); } if (this.core.getAttribute(child, 'transitionMethod') === '') { nameAndViolations.violations.push({ node: child, message: 'Attribute transitionMethod of transition [' + childName + '] is not defined. ' + 'Please define transitionMethod.' }); } } if (self.isMetaTypeOf(child, self.META.EnforceableTransition) || self.isMetaTypeOf(child, self.META.SpontaneousTransition)) { if (nameAndViolations.transitionNames.hasOwnProperty(childName)) { nameAndViolations.violations.push({ node: child, message: 'Name [' + childName + '] of transition is not unique. ' + 'Please rename. Enforceable and spontaneous transitions of the same component ' + 'type must have unique names.' }); } nameAndViolations.transitionNames[childName] = self.core.getPath(child); } if (self.isMetaTypeOf(child, self.META.Guard)) { if (nameAndViolations.guardNames.hasOwnProperty(childName)) { nameAndViolations.violations.push({ node: child, message: 'Name [' + childName + '] of guard is not unique. Please rename. ' + 'Guards of the same component type must have unique names.' }); } nameAndViolations.guardNames[childName] = self.core.getPath(child); if (self.core.getAttribute(child, 'guardMethod') === '') { nameAndViolations.violations.push({ node: child, message: 'Attribute guardMethod of transition [' + childName + '] is not defined. ' + 'Please define guardMethod.' }); } } return nameAndViolations; }; return BehaviorSpecGenerator; });