exportmmtomd.js 9.6 KB

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