Code.js 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. /* globals prettyPrintOne, vkbeautify */
  2. /**
  3. * Code operations.
  4. *
  5. * @author n1474335 [n1474335@gmail.com]
  6. * @copyright Crown Copyright 2016
  7. * @license Apache-2.0
  8. *
  9. * @namespace
  10. */
  11. var Code = {
  12. /**
  13. * @constant
  14. * @default
  15. */
  16. LANGUAGES: ["default-code", "default-markup", "bash", "bsh", "c", "cc", "coffee", "cpp", "cs", "csh", "cv", "cxx", "cyc", "htm", "html", "in.tag", "java", "javascript", "js", "json", "m", "mxml", "perl", "pl", "pm", "py", "python", "rb", "rc", "rs", "ruby", "rust", "sh", "uq.val", "xhtml", "xml", "xsl"],
  17. /**
  18. * @constant
  19. * @default
  20. */
  21. LINE_NUMS: false,
  22. /**
  23. * Syntax highlighter operation.
  24. *
  25. * @param {string} input
  26. * @param {Object[]} args
  27. * @returns {html}
  28. */
  29. run_syntax_highlight: function(input, args) {
  30. var language = args[0],
  31. line_nums = args[1];
  32. return "<code class='prettyprint'>" + prettyPrintOne(Utils.escape_html(input), language, line_nums) + "</code>";
  33. },
  34. /**
  35. * @constant
  36. * @default
  37. */
  38. BEAUTIFY_INDENT: "\\t",
  39. /**
  40. * XML Beautify operation.
  41. *
  42. * @param {string} input
  43. * @param {Object[]} args
  44. * @returns {string}
  45. */
  46. run_xml_beautify: function(input, args) {
  47. var indent_str = args[0];
  48. return vkbeautify.xml(input, indent_str);
  49. },
  50. /**
  51. * JSON Beautify operation.
  52. *
  53. * @param {string} input
  54. * @param {Object[]} args
  55. * @returns {string}
  56. */
  57. run_json_beautify: function(input, args) {
  58. var indent_str = args[0];
  59. if (!input) return "";
  60. return vkbeautify.json(input, indent_str);
  61. },
  62. /**
  63. * CSS Beautify operation.
  64. *
  65. * @param {string} input
  66. * @param {Object[]} args
  67. * @returns {string}
  68. */
  69. run_css_beautify: function(input, args) {
  70. var indent_str = args[0];
  71. return vkbeautify.css(input, indent_str);
  72. },
  73. /**
  74. * SQL Beautify operation.
  75. *
  76. * @param {string} input
  77. * @param {Object[]} args
  78. * @returns {string}
  79. */
  80. run_sql_beautify: function(input, args) {
  81. var indent_str = args[0];
  82. return vkbeautify.sql(input, indent_str);
  83. },
  84. /**
  85. * @constant
  86. * @default
  87. */
  88. PRESERVE_COMMENTS: false,
  89. /**
  90. * XML Minify operation.
  91. *
  92. * @param {string} input
  93. * @param {Object[]} args
  94. * @returns {string}
  95. */
  96. run_xml_minify: function(input, args) {
  97. var preserve_comments = args[0];
  98. return vkbeautify.xmlmin(input, preserve_comments);
  99. },
  100. /**
  101. * JSON Minify operation.
  102. *
  103. * @param {string} input
  104. * @param {Object[]} args
  105. * @returns {string}
  106. */
  107. run_json_minify: function(input, args) {
  108. if (!input) return "";
  109. return vkbeautify.jsonmin(input);
  110. },
  111. /**
  112. * CSS Minify operation.
  113. *
  114. * @param {string} input
  115. * @param {Object[]} args
  116. * @returns {string}
  117. */
  118. run_css_minify: function(input, args) {
  119. var preserve_comments = args[0];
  120. return vkbeautify.cssmin(input, preserve_comments);
  121. },
  122. /**
  123. * SQL Minify operation.
  124. *
  125. * @param {string} input
  126. * @param {Object[]} args
  127. * @returns {string}
  128. */
  129. run_sql_minify: function(input, args) {
  130. return vkbeautify.sqlmin(input);
  131. },
  132. /**
  133. * Generic Code Beautify operation.
  134. *
  135. * Yeeeaaah...
  136. *
  137. * I'm not proud of this code, but seriously, try writing a generic lexer and parser that
  138. * correctly generates an AST for multiple different languages. I have tried, and I can tell
  139. * you it's pretty much impossible.
  140. *
  141. * This basically works. That'll have to be good enough. It's not meant to produce working code,
  142. * just slightly more readable code.
  143. *
  144. * Things that don't work:
  145. * - For loop formatting
  146. * - Do-While loop formatting
  147. * - Switch/Case indentation
  148. * - Bit shift operators
  149. *
  150. * @author n1474335 [n1474335@gmail.com]
  151. * @param {string} input
  152. * @param {Object[]} args
  153. * @returns {string}
  154. */
  155. run_generic_beautify: function(input, args) {
  156. var code = input,
  157. t = 0,
  158. preserved_tokens = [],
  159. m;
  160. // Remove strings
  161. var sstrings = /'([^'\\]|\\.)*'/g;
  162. while ((m = sstrings.exec(code))) {
  163. code = preserve_token(code, m, t++);
  164. sstrings.lastIndex = m.index;
  165. }
  166. var dstrings = /"([^"\\]|\\.)*"/g;
  167. while ((m = dstrings.exec(code))) {
  168. code = preserve_token(code, m, t++);
  169. dstrings.lastIndex = m.index;
  170. }
  171. // Remove comments
  172. var scomments = /\/\/[^\n\r]*/g;
  173. while ((m = scomments.exec(code))) {
  174. code = preserve_token(code, m, t++);
  175. scomments.lastIndex = m.index;
  176. }
  177. var mcomments = /\/\*[\s\S]*?\*\//gm;
  178. while ((m = mcomments.exec(code))) {
  179. code = preserve_token(code, m, t++);
  180. mcomments.lastIndex = m.index;
  181. }
  182. var hcomments = /(^|\n)#[^\n\r#]+/g;
  183. while ((m = hcomments.exec(code))) {
  184. code = preserve_token(code, m, t++);
  185. hcomments.lastIndex = m.index;
  186. }
  187. // Remove regexes
  188. var regexes = /\/.*?[^\\]\/[gim]{0,3}/gi;
  189. while ((m = regexes.exec(code))) {
  190. code = preserve_token(code, m, t++);
  191. regexes.lastIndex = m.index;
  192. }
  193. // Create newlines after ;
  194. code = code.replace(/;/g, ";\n");
  195. // Create newlines after { and around }
  196. code = code.replace(/{/g, "{\n");
  197. code = code.replace(/}/g, "\n}\n");
  198. // Remove carriage returns
  199. code = code.replace(/\r/g, "");
  200. // Remove all indentation
  201. code = code.replace(/^\s+/g, "");
  202. code = code.replace(/\n\s+/g, "\n");
  203. // Remove trailing spaces
  204. code = code.replace(/\s*$/g, "");
  205. // Remove newlines before {
  206. code = code.replace(/\n{/g, "{");
  207. // Indent
  208. var i = 0,
  209. level = 0;
  210. while (i < code.length) {
  211. switch(code[i]) {
  212. case "{":
  213. level++;
  214. break;
  215. case "\n":
  216. if (i+1 >= code.length) break;
  217. if (code[i+1] === "}") level--;
  218. var indent = (level >= 0) ? Array(level*4+1).join(" ") : "";
  219. code = code.substring(0, i+1) + indent + code.substring(i+1);
  220. if (level > 0) i += level*4;
  221. break;
  222. }
  223. i++;
  224. }
  225. // Add strategic spaces
  226. code = code.replace(/\s*([!<>=+-/*]?)=\s*/g, " $1= ");
  227. code = code.replace(/\s*<([=]?)\s*/g, " <$1 ");
  228. code = code.replace(/\s*>([=]?)\s*/g, " >$1 ");
  229. code = code.replace(/([^+])\+([^+=])/g, "$1 + $2");
  230. code = code.replace(/([^-])-([^-=])/g, "$1 - $2");
  231. code = code.replace(/([^*])\*([^*=])/g, "$1 * $2");
  232. code = code.replace(/([^/])\/([^/=])/g, "$1 / $2");
  233. code = code.replace(/\s*,\s*/g, ", ");
  234. code = code.replace(/\s*{/g, " {");
  235. code = code.replace(/}\n/g, "}\n\n");
  236. // Just... don't look at this
  237. code = code.replace(/(if|for|while|with|elif|elseif)\s*\(([^\n]*)\)\s*\n([^{])/gim, "$1 ($2)\n $3");
  238. code = code.replace(/(if|for|while|with|elif|elseif)\s*\(([^\n]*)\)([^{])/gim, "$1 ($2) $3");
  239. code = code.replace(/else\s*\n([^{])/gim, "else\n $1");
  240. code = code.replace(/else\s+([^{])/gim, "else $1");
  241. // Remove strategic spaces
  242. code = code.replace(/\s+;/g, ";");
  243. code = code.replace(/\{\s+\}/g, "{}");
  244. code = code.replace(/\[\s+\]/g, "[]");
  245. code = code.replace(/}\s*(else|catch|except|finally|elif|elseif|else if)/gi, "} $1");
  246. // Replace preserved tokens
  247. var ptokens = /###preserved_token(\d+)###/g;
  248. while ((m = ptokens.exec(code))) {
  249. var ti = parseInt(m[1], 10);
  250. code = code.substring(0, m.index) + preserved_tokens[ti] + code.substring(m.index + m[0].length);
  251. ptokens.lastIndex = m.index;
  252. }
  253. return code;
  254. function preserve_token(str, match, t) {
  255. preserved_tokens[t] = match[0];
  256. return str.substring(0, match.index) +
  257. "###preserved_token" + t + "###" +
  258. str.substring(match.index + match[0].length);
  259. }
  260. },
  261. };