exporttosccdxml_debug.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
  1. /* SCCDXML exporter plugin*/
  2. const {
  3. __errorContinuable,
  4. __httpReq,
  5. __wHttpReq,
  6. __postInternalErrorMsg, __postMessage,
  7. __sequenceNumber,
  8. __successContinuable,
  9. __uri_to_id
  10. } = require("../__worker");
  11. const _do = require("../___do");
  12. const _utils = require('../utils');
  13. const _mmmk = require("../mmmk");
  14. const _fs = _do.convert(require('fs'), ['readFile', 'writeFile', 'readdir']);
  15. const _fspp = _do.convert(require('../___fs++'), ['mkdirs']);
  16. module.exports = {
  17. 'interfaces' : [{'method':'POST', 'url=':'/exporttosccdxml_debug'}],
  18. 'csworker' :
  19. function(resp,method,uri,reqData,wcontext)
  20. {
  21. var self = this,
  22. actions = [__wHttpReq('GET','/current.model?wid='+wcontext.__aswid)];
  23. _do.chain(actions)(
  24. function(asdata){
  25. var writeActions = [_fspp.mkdirs('./exported_to_sccdxml/classes/')];
  26. _do.chain(writeActions) (
  27. function() {
  28. var file_contents = '',
  29. as = _utils.jsonp(asdata['data']),
  30. type_map = {},
  31. type_map_keys = {},
  32. incoming = {},
  33. outgoing = {};
  34. for (var key in as.nodes) {
  35. var node = as.nodes[key];
  36. if (!(node['$type'] in type_map)) {
  37. type_map[node['$type']] = [];
  38. type_map_keys[node['$type']] = [];
  39. }
  40. type_map[node['$type']].push(node);
  41. type_map_keys[node['$type']].push(key);
  42. node['$key'] = key;
  43. }
  44. function xml_safe(str) {
  45. return str.replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;");
  46. }
  47. function safe_add(l, el) {
  48. if (l.indexOf(el) == -1) {
  49. l.push(el);
  50. }
  51. }
  52. function find_initial(state){
  53. var substates = outgoing[state['$key']].filter(function(el) {return as.nodes[el]['$type'] == '/Formalisms/SCCD/SCCD/contain' || as.nodes[el]['$type'] == '/Formalisms/SCCD/SCCD/ocContain';}).map(function(tid) {return as.nodes[tid];});
  54. for (var sidx in substates){
  55. var substate = as.nodes[outgoing[substates[sidx]['$key']]];
  56. if(substate['isStart']['value']){
  57. return substate['name']['value'];
  58. }
  59. }
  60. }
  61. function get_full_path(state){
  62. var parent_link = incoming[state['$key']].filter(function(el) {return as.nodes[el]['$type'] == '/Formalisms/SCCD/SCCD/contain' || as.nodes[el]['$type'] == '/Formalisms/SCCD/SCCD/ocContain' || as.nodes[el]['$type'] == '/Formalisms/SCCD/SCCD/containOC' || as.nodes[el]['$type'] == '/Formalisms/SCCD/SCCD/includes';}).map(function(tid) {return as.nodes[tid];})[0];
  63. if (parent_link != undefined){
  64. var parent = as.nodes[incoming[parent_link['$key']][0]];
  65. return get_full_path(parent).concat([state['name']['value']]);
  66. }
  67. else{
  68. return [state['name']['value']];
  69. }
  70. }
  71. function find_path(source, destination){
  72. if(source['$key'] == destination['$key']){
  73. return ".";
  74. }
  75. // Resolve absolute path of source
  76. source_path = get_full_path(source);
  77. // Resolve absolute path of destination
  78. destination_path = get_full_path(destination);
  79. // Now make the destination path relative to the source path
  80. var common;
  81. for (var i in source_path){
  82. if(source_path[i] != destination_path[i]){
  83. common = i;
  84. break;
  85. }
  86. }
  87. source_path = source_path.slice(i, source_path.length);
  88. destination_path = destination_path.slice(i, destination_path.length);
  89. var result = ".";
  90. for (var i in source_path){
  91. result += "/..";
  92. }
  93. for (var i in destination_path){
  94. result += "/" + destination_path[i];
  95. }
  96. return result;
  97. }
  98. function write_raise(lst){
  99. let contents = "";
  100. for(var ridx in lst){
  101. var r = lst[ridx];
  102. contents += '<raise event="' + r['event'] + '"';
  103. if(r['scope'].length == 0){
  104. contents += ' scope="broad">\n';
  105. }
  106. else if(r['scope'].lastIndexOf("output(", 0) === 0){
  107. contents += ' scope="output" port="' + r['scope'].slice(7, -1)+ '">\n';
  108. }
  109. else{
  110. contents += ' scope="' + r['scope'] + '">\n';
  111. }
  112. let args = r['arguments'];
  113. for (var aidx in args){
  114. var arg = args[aidx];
  115. if(arg != ""){
  116. contents += '<parameter expr="' + xml_safe(arg) + '"/>\n';
  117. }
  118. }
  119. contents += '</raise>\n';
  120. }
  121. return contents;
  122. }
  123. function resolve_transitions(state){
  124. contents = "";
  125. if(outgoing[state['$key']] == undefined){
  126. return "";
  127. }
  128. var transitions = outgoing[state['$key']].filter(function(el) {return as.nodes[el]['$type'] == '/Formalisms/SCCD/SCCD/transition';}).map(function(tid) {return as.nodes[tid];});
  129. for (var tidx in transitions){
  130. var transition = transitions[tidx];
  131. contents += "<transition ";
  132. if(transition['after']['value'].length > 0){
  133. contents += 'after="' + xml_safe(transition['after']['value']) + '" ';
  134. }
  135. if(transition['event']['value'].length > 0){
  136. contents += 'event="' + transition['event']['value'] + '" ';
  137. }
  138. if(transition['guard']['value'].length > 0){
  139. contents += 'cond="' + xml_safe(transition['guard']['value']) + '" ';
  140. }
  141. if(transition['port']['value'].length > 0){
  142. contents += 'port="' + transition['port']['value'] + '" ';
  143. }
  144. var target = as.nodes[outgoing[transition['$key']][0]];
  145. contents += 'target="' + find_path(state, target) + '" ';
  146. contents += '>\n';
  147. var parameters = transition['parameters']['value'];
  148. for(var pidx in parameters){
  149. var param = parameters[pidx];
  150. contents += '<parameter name="' + param + '"/>\n';
  151. }
  152. if(transition['action']['value'].length > 0){
  153. contents += "<script><![CDATA[";
  154. contents += transition['action']['value'].split("/*newline*/").join("\n");
  155. contents += "]]></script>\n";
  156. }
  157. var raise = transition['raise']['value'];
  158. contents += write_raise(raise);
  159. contents += '</transition>\n';
  160. }
  161. return contents;
  162. }
  163. function find_priority(state){
  164. state = as.nodes[state['$key']];
  165. if(state['option']['value'] == "OTF"){
  166. return "source_parent";
  167. }
  168. else if(state['option']['value'] == "ITF"){
  169. return "source_child";
  170. }
  171. else {
  172. console.log("Unknown conflict resolution selected: " + state['option']['value']);
  173. return "undefined";
  174. }
  175. }
  176. function add_actions(state){
  177. contents = "<onentry>\n";
  178. state = as.nodes[state['$key']];
  179. if(state['entryAction'] == undefined){
  180. return "";
  181. }
  182. contents += "<script><![CDATA[";
  183. if(state['$type'] == "/Formalisms/SCCD/SCCD/BasicState"){
  184. contents += "if True:\n";
  185. contents += " data = json.dumps({'text':'CLIENT_BDAPI :: {\"func\":\"_highlightState\",\"args\":{\"asid\":\"" + state['$key'] + "\",\"followCrossFormalismLinks\":\"*\"}}'})\n";
  186. contents += " headers = {'Content-Type': 'text/plain'}\n";
  187. contents += " conn = httplib.HTTPConnection('127.0.0.1:8124')\n";
  188. contents += " conn.request('PUT', '/GET/console?wid=" + wcontext.__aswid + "', data, headers)\n";
  189. contents += " conn.getresponse()\n";
  190. contents += " conn.close()\n";
  191. contents += "else:\n";
  192. contents += " pass\n";
  193. }
  194. else{
  195. // To prevent crashes of the compiler
  196. contents += "pass\n";
  197. }
  198. if(state['entryAction']['value'].length > 0){
  199. contents += state['entryAction']['value'].split("/*newline*/").join("\n");
  200. }
  201. contents += "]]></script>\n";
  202. var raise = state['raiseEntry']['value'];
  203. contents += write_raise(raise);
  204. contents += "</onentry>\n";
  205. contents += "<onexit>\n";
  206. contents += "<script><![CDATA[";
  207. if(state['$type'] == "/Formalisms/SCCD/SCCD/BasicState"){
  208. contents += "if True:\n";
  209. contents += " data = json.dumps({'text':'CLIENT_BDAPI :: {\"func\":\"_unhighlightState\",\"args\":{\"asid\":\"" + state['$key'] + "\"}}'})\n";
  210. contents += " headers = {'Content-Type': 'text/plain'}\n";
  211. contents += " conn = httplib.HTTPConnection('127.0.0.1:8124')\n";
  212. contents += " conn.request('PUT', '/GET/console?wid=" + wcontext.__aswid + "', data, headers)\n";
  213. contents += " conn.getresponse()\n";
  214. contents += " conn.close()\n";
  215. contents += "else:\n";
  216. contents += " pass\n";
  217. }
  218. else{
  219. // To prevent crashes of the compiler
  220. contents += "pass\n";
  221. }
  222. if(state['exitAction']['value'].length > 0){
  223. contents += state['exitAction']['value'].split("/*newline*/").join("\n");
  224. }
  225. contents += "]]></script>\n";
  226. var raise = state['raiseExit']['value'];
  227. contents += write_raise(raise);
  228. contents += "</onexit>\n";
  229. return contents;
  230. }
  231. function recursive(state, is_root){
  232. var contents = "";
  233. if(outgoing[state['$key']] == undefined){
  234. var containOC = [],
  235. contain = [],
  236. ocContain = [];
  237. }
  238. else{
  239. var containOC = outgoing[state['$key']].filter(function(el) {return as.nodes[el]['$type'] == '/Formalisms/SCCD/SCCD/containOC';}).map(function(tid) {return as.nodes[tid];});
  240. var contain = outgoing[state['$key']].filter(function(el) {return as.nodes[el]['$type'] == '/Formalisms/SCCD/SCCD/contain';}).map(function(tid) {return as.nodes[tid];});
  241. var ocContain = outgoing[state['$key']].filter(function(el) {return as.nodes[el]['$type'] == '/Formalisms/SCCD/SCCD/ocContain';}).map(function(tid) {return as.nodes[tid];});
  242. var history = outgoing[state['$key']].filter(function(el) {return as.nodes[el]['$type'] == '/Formalisms/SCCD/SCCD/includes';}).map(function(tid) {return as.nodes[tid];});
  243. }
  244. var s = as.nodes[state['$key']];
  245. if (is_root){
  246. contents += '<scxml initial="' + find_initial(s) + '" priority="' + find_priority(s) + '">\n';
  247. var children = containOC.concat(contain).concat(ocContain).concat(history);
  248. console.log("Children of root: " + children);
  249. for (var cidx in children){
  250. var child = as.nodes[outgoing[children[cidx]['$key']]];
  251. contents += recursive(child, false);
  252. }
  253. contents += resolve_transitions(s);
  254. contents += '</scxml>\n';
  255. }
  256. else if (containOC.length > 0){
  257. contents += '<parallel id="' + s['name']['value'] + '">\n';
  258. var children = containOC.concat(contain).concat(ocContain).concat(history);
  259. for (var cidx in children){
  260. var child = as.nodes[outgoing[children[cidx]['$key']]];
  261. contents += recursive(child, false);
  262. }
  263. contents += resolve_transitions(s);
  264. contents += add_actions(s);
  265. contents += '</parallel>\n';
  266. }
  267. else if(contain.length + ocContain.length > 0){
  268. contents += '<state id="' + s['name']['value'] + '" initial="' + find_initial(s) + '">\n';
  269. var children = containOC.concat(contain).concat(ocContain).concat(history);
  270. for (var cidx in children){
  271. var child = as.nodes[outgoing[children[cidx]['$key']]];
  272. contents += recursive(child, false);
  273. }
  274. contents += resolve_transitions(s);
  275. contents += add_actions(s);
  276. contents += '</state>\n';
  277. }
  278. else {
  279. var history = incoming[state['$key']].filter(function(el) {return as.nodes[el]['$type'] == '/Formalisms/SCCD/SCCD/includes';}).map(function(tid) {return as.nodes[tid];});
  280. if (history.length > 0){
  281. contents += '<history id="' + s['name']['value'] + '" type="' + s['type']['value'].trim() + '"/>\n';
  282. }
  283. else{
  284. contents += '<state id="' + s['name']['value'] + '">\n';
  285. contents += resolve_transitions(s);
  286. contents += add_actions(s);
  287. contents += '</state>\n';
  288. }
  289. }
  290. return contents;
  291. }
  292. function calc_in_out_rel(rel_type) {
  293. for (var idx in type_map_keys[rel_type]) {
  294. key = type_map_keys[rel_type][idx];
  295. incoming[key] = [];
  296. outgoing[key] = [];
  297. for (var e_key in as.edges) {
  298. var e = as.edges[e_key];
  299. if (e['dest'] == key) {
  300. safe_add(incoming[key], e['src']);
  301. if (!(e['src'] in outgoing)) {
  302. outgoing[e['src']] = [];
  303. }
  304. safe_add(outgoing[e['src']], key);
  305. }
  306. if (e['src'] == key) {
  307. safe_add(outgoing[key], e['dest']);
  308. if (!(e['dest'] in incoming)) {
  309. incoming[e['dest']] = [];
  310. }
  311. safe_add(incoming[e['dest']], key);
  312. }
  313. }
  314. }
  315. }
  316. calc_in_out_rel('/Formalisms/SCCD/SCCD/transition');
  317. calc_in_out_rel('/Formalisms/SCCD/SCCD/Inheritance');
  318. calc_in_out_rel('/Formalisms/SCCD/SCCD/Association');
  319. calc_in_out_rel('/Formalisms/SCCD/SCCD/contain');
  320. calc_in_out_rel('/Formalisms/SCCD/SCCD/containOC');
  321. calc_in_out_rel('/Formalisms/SCCD/SCCD/ocContain');
  322. calc_in_out_rel('/Formalisms/SCCD/SCCD/behaviour');
  323. calc_in_out_rel('/Formalisms/SCCD/SCCD/includes');
  324. for (var key in type_map['/Formalisms/SCCD/SCCD/Class']){
  325. var node = type_map['/Formalisms/SCCD/SCCD/Class'][key],
  326. external = node['external']['value'],
  327. type = node['name']['value'];
  328. if(!external){
  329. file_contents += '<class name="' + node['name']['value'] + '" default="true">\n';
  330. file_contents += '\t<relationships>\n';
  331. inheritances = outgoing[node['$key']].filter(function(el) {return as.nodes[el]['$type'] == '/Formalisms/SCCD/SCCD/Inheritance';}).map(function(tid) {return as.nodes[tid];});
  332. for (var iidx in inheritances){
  333. target = as.nodes[outgoing[inheritances[iidx]['$key']][0]];
  334. file_contents += '\t\t<inheritance class="' + target['name']['value'] + '"/>\n';
  335. }
  336. associations = outgoing[node['$key']].filter(function(el) {return as.nodes[el]['$type'] == '/Formalisms/SCCD/SCCD/Association';}).map(function(tid) {return as.nodes[tid];});
  337. for (var iidx in associations){
  338. target = as.nodes[outgoing[associations[iidx]['$key']][0]];
  339. file_contents += '\t\t<association name="' + associations[iidx]['name']['value'] + '" class="' + target['name']['value'] + '"/>\n';
  340. }
  341. file_contents += '';
  342. file_contents += '\t</relationships>\n';
  343. for (var fidx in node['methods']['value']){
  344. var func = node['methods']['value'][fidx];
  345. file_contents += '\t<method name="' + func['name'] + '">\n';
  346. for (var aidx in func['args']){
  347. var arg = func['args'][aidx];
  348. if(arg['name'] == ""){
  349. continue;
  350. }
  351. file_contents += '\t\t<parameter name="' + arg['name'] + '"/>\n';
  352. }
  353. file_contents += '\t<body><![CDATA[';
  354. file_contents += func['body'].split("/*newline*/").join("\n");
  355. file_contents += "\n";
  356. if(func['name'] == node['name']['value']){
  357. file_contents += "if True:\n";
  358. file_contents += "\tdata = json.dumps({'text':'CLIENT_BDAPI :: {\"func\":\"_unhighlight\",\"args\":{}}'})\n";
  359. file_contents += "\theaders = {'Content-Type': 'text/plain'}\n";
  360. file_contents += "\tconn = httplib.HTTPConnection('127.0.0.1:8124')\n";
  361. file_contents += "\tconn.request('PUT', '/GET/console?wid=" + wcontext.__aswid + "', data, headers)\n";
  362. file_contents += "\tconn.getresponse()\n";
  363. file_contents += "\tconn.close()\n";
  364. file_contents += "else:\n";
  365. file_contents += "\tpass\n";
  366. }
  367. file_contents += '\t]]></body>\n';
  368. file_contents += '\t</method>\n';
  369. }
  370. var behaviour = outgoing[node['$key']].filter(function(el) {return as.nodes[el]['$type'] == '/Formalisms/SCCD/SCCD/behaviour';}).map(function(tid) {return as.nodes[tid];});
  371. var statechart = as.nodes[outgoing[behaviour[0]['$key']][0]];
  372. file_contents += recursive(statechart, true);
  373. file_contents += '</class>\n';
  374. }
  375. }
  376. _fs.writeFileSync('./exported_to_sccdxml/classes/model.xml', file_contents);
  377. __postMessage({'statusCode': 200,
  378. 'respIndex': resp});
  379. },
  380. function(writeErr) {__postInternalErrorMsg(resp, writeErr);}
  381. );
  382. },
  383. function(err) {__postInternalErrorMsg(resp, err);}
  384. );
  385. },
  386. 'asworker' :
  387. function(resp,method,uri,reqData,wcontext)
  388. {
  389. this.localcontext.counter++;
  390. __postMessage(
  391. {'statusCode':200,
  392. 'respIndex':resp});
  393. }
  394. };