exportmmtomd.js 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. {
  2. 'interfaces': [{'method':'POST', 'url=':'/exportmmtomd'}],
  3. 'csworker':
  4. function(resp, method, uri, reqData, wcontext) {
  5. var actions = [__wHttpReq('GET', '/current.model?wid=' + wcontext.__aswid)];
  6. _do.chain(actions) (
  7. function(asdata) {
  8. var writeActions = [_fspp.mkdirs('./exported_to_md/')];
  9. _do.chain(writeActions) (
  10. function() {
  11. var file_contents = '';
  12. var as = _utils.jsonp(asdata['data']);
  13. var edges = {};
  14. var superclasses = {};
  15. var superclasses_ids = {};
  16. // R: Replace $* by Node ($* is the wildcard class of AToMPM: metaDepth's Node)
  17. // R: This is still not 100% safe since Node is no longer in the reservedWordsPattern,
  18. // so a class could be called Node in atompm and give a compilation error in metadepth
  19. for (var key in as.nodes) {
  20. var node = as.nodes[key];
  21. if (node.name != null && node.name.value == '$*') {
  22. node.name.value = 'Node';
  23. }
  24. }
  25. /*
  26. R: Start variable name fixing
  27. */
  28. var reservedWordsPattern = /(Sequence|Model|Edge|Link)/;
  29. var escapes = [[/\//g, "\\\/"], [/\\/g, "\\\\"]];
  30. var nonWordCharPattern = /\W/g; // A word character is a character from a-z, A-Z, 0-9, including the _ (underscore) character.
  31. function fixName(name) {
  32. name = name.replace(nonWordCharPattern, '_');
  33. var matchArr = name.match(reservedWordsPattern);
  34. if (matchArr != null) {
  35. name = name.replace(matchArr[0], matchArr[0] + '0');
  36. }
  37. return name;
  38. }
  39. function escapeString(str) {
  40. for (i in escapes) {
  41. str = str.replace(escapes[i][0], escapes[i][1]);
  42. }
  43. return str;
  44. }
  45. for (var key in as.nodes) {
  46. // All names of Nodes
  47. // console.log(as);
  48. var node = as.nodes[key];
  49. if (node.name != null) {
  50. node.name.value = fixName(node.name.value);
  51. // console.log(node.name);
  52. // console.log(node.attributes);
  53. if (node.attributes != null) {
  54. for (var prop in node.attributes['value']) {
  55. // All names of attributes and (default) values
  56. node.attributes['value'][prop].name = fixName(node.attributes['value'][prop].name);
  57. if (node.attributes['value'][prop].type == 'string' | node.attributes['value'][prop].type == 'code')
  58. node.attributes['value'][prop]['default'] = escapeString(node.attributes['value'][prop]['default']);
  59. }
  60. }
  61. }
  62. }
  63. /*
  64. R: End variable name fixing
  65. */
  66. extract_md_type = function(mm) {
  67. mm_parts = mm.split('/');
  68. return fixName(mm_parts[mm_parts.length - 1]); // R: Add fixName() here to apply it to types as well
  69. };
  70. for (var i = 0; i < as.edges.length; i += 2) {
  71. if (as.edges[i].dest != as.edges[i + 1].src) console.error('The source and destination of the edge are different!');
  72. if (extract_md_type(as.nodes[as.edges[i].dest]['$type']) == 'Inheritance') {
  73. if (!(as.edges[i].src in superclasses)) {
  74. superclasses[as.edges[i].src] = [];
  75. superclasses_ids[as.edges[i].src] = [];
  76. }
  77. superclasses[as.edges[i].src].push(as.nodes[as.edges[i + 1].dest]['name']['value']);
  78. superclasses_ids[as.edges[i].src].push(as.edges[i + 1].dest);
  79. } else {
  80. edges[as.edges[i].dest] = ([as.edges[i].src, as.edges[i + 1].dest]);
  81. }
  82. };
  83. // Add superclass Link to all Edges (this is class is not present in AToMPM thus not contained in as.nodes)
  84. for (var key in as.nodes) {
  85. // console.log(key);
  86. var node = as.nodes[key];
  87. if (key in edges) {
  88. superclasses[key] = ['Link'];
  89. }
  90. }
  91. file_contents += 'Model ' + reqData['name'] + ' {\n'
  92. var sorted_nodes = [];
  93. var sorted_edges = [];
  94. var nodes_no_superclasses = [];
  95. var c_to_superclass = {}
  96. // copy superclasses dictionary
  97. for (var key in superclasses_ids) {
  98. c_to_superclass[key] = superclasses_ids[key].slice(0);
  99. }
  100. // create reverse of superclasses: mapping of class to its subclasses
  101. var c_to_subclasses = {};
  102. for (var key in superclasses_ids) {
  103. // console.error(superclasses_ids[key]);
  104. for (var i in superclasses_ids[key]) {
  105. var sc = superclasses_ids[key][i];
  106. if (!(sc in c_to_subclasses)) {
  107. c_to_subclasses[sc] = [];
  108. }
  109. c_to_subclasses[sc].push(key);
  110. }
  111. }
  112. // get all nodes without any superclasses
  113. for (var key in as.nodes) {
  114. if (!(key in superclasses_ids)) {
  115. nodes_no_superclasses.push(key)
  116. }
  117. }
  118. // topological sort
  119. while (nodes_no_superclasses.length > 0) {
  120. var n = nodes_no_superclasses.pop();
  121. if (n in edges) {
  122. sorted_edges.push(n);
  123. } else {
  124. sorted_nodes.push(n);
  125. }
  126. for (var i in c_to_subclasses[n]) {
  127. sc = c_to_subclasses[n][i];
  128. // console.error(c_to_superclass[sc]);
  129. c_to_superclass[sc].splice(c_to_superclass[sc].indexOf(n), 1);
  130. // console.error(c_to_superclass[sc]);
  131. if (c_to_superclass[sc].length == 0) {
  132. nodes_no_superclasses.push(sc);
  133. }
  134. }
  135. }
  136. sorted_nodes = sorted_nodes.concat(sorted_edges);
  137. // console.log('as.nodes:');
  138. // console.log(as.nodes);
  139. // console.log('as.edges:');
  140. // console.log(as.edges);
  141. // console.log('edges:');
  142. // console.log(edges);
  143. // If there is at least an edge in the model, add the Link superclass since all edges will extend it
  144. // console.log(edges);
  145. if (edges !== {}) { // BUG: This check is currently not working.
  146. file_contents +=
  147. 'Node Link {\n' +
  148. 'src : Node;\n' +
  149. 'dst : Node;\n' +
  150. '}\n';
  151. }
  152. while (sorted_nodes.length > 0) {
  153. key = sorted_nodes.shift();
  154. var node = as.nodes[key];
  155. if (!(node["$type"].search('GlobalConstraint') >= 0 || node["$type"].search('GlobalAction') >= 0 || node["$type"].search('Inheritance') >= 0|| node.name.value == "Node")) {
  156. // if (key in edges) {
  157. /*
  158. var incoming, outgoing;
  159. for (var e in edges) {
  160. if (edges[e][0] == key) {
  161. outgoing = edges[e][1];
  162. } else if (edges[e][1] == key) {
  163. incoming = edges[e][0];
  164. }
  165. }
  166. */
  167. // var incoming = [];
  168. // var outgoing = [];
  169. // for (var e in edges) {
  170. // if (edges[e][0] == key) {
  171. // outgoing.push(e);
  172. // }
  173. // if (edges[e][1] == key) {
  174. // incoming.push(e);
  175. // }
  176. // }
  177. // No abstract classes in pattern metamodel (RAMification)
  178. file_contents += 'Node '
  179. + node.name.value
  180. + (key in superclasses ? ': ' + superclasses[key].join(', ') : ' ')
  181. + '{\n';
  182. // if (incoming.length) {
  183. // file_contents +=
  184. // incoming.map(function(i) {return 'in' + as.nodes[i].name.value +
  185. // ': ' + as.nodes[edges[i][0]]['name']['value'] + '[*];'}).join('\n')
  186. // + '\n';
  187. // }
  188. // if (outgoing.length) {
  189. // file_contents +=
  190. // outgoing.map(function(i) {return 'out' + as.nodes[i].name.value +
  191. // ': ' + as.nodes[edges[i][1]]['name']['value'] + '[*];'}).join('\n')
  192. // + '\n';
  193. // }
  194. var typemapping = {
  195. 'bool': 'boolean',
  196. 'string': 'String',
  197. 'list<string>': 'String[*]',
  198. 'list<bool>': 'boolean[*]',
  199. 'list<int>': 'int[*]',
  200. 'list<float>': 'double[*]',
  201. 'list<double>': 'double[*]',
  202. 'list<real>': 'double[*]',
  203. 'code': 'String'
  204. }
  205. // DEPRECATED: No longer needed after adding the Link Node
  206. // if (key in edges) {
  207. // file_contents += 'in : ' + as.nodes[edges[key][0]]['name']['value'] +';\n';
  208. // file_contents += 'out : ' + as.nodes[edges[key][1]]['name']['value'] +';\n';
  209. // }
  210. for (var prop in node.attributes['value']) {
  211. t = node.attributes['value'][prop].type;
  212. file_contents += node.attributes['value'][prop].name + ':' + (t in typemapping ? typemapping[t] : t) + (node.attributes['value'][prop]['default'] != '' ? ' = ' + (t.search('list') >= 0 ? '[' : '') + node.attributes['value'][prop]['default'] + (t.search('list') >= 0 ? ']' : '') : '') + ';\n';
  213. }
  214. file_contents += '}\n';
  215. };
  216. };
  217. file_contents += '}\n';
  218. _fs.writeFileSync('./exported_to_md/' + reqData['name'] + '.mdepth', file_contents);
  219. __postMessage({ 'statusCode': 200,
  220. 'respIndex': resp});
  221. },
  222. function(writeErr) {__postInternalErrorMsg(resp, writeErr);}
  223. );
  224. },
  225. function(err) {__postInternalErrorMsg(resp, err);}
  226. )
  227. },
  228. 'asworker':
  229. function(resp, method, uri, reqData, wcontext)
  230. {
  231. __postMessage(
  232. {'statusCode': 200,
  233. 'respIndex': resp});
  234. }
  235. }