javascript_worker.js 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. /* ***** BEGIN LICENSE BLOCK *****
  2. * Distributed under the BSD license:
  3. *
  4. * Copyright (c) 2010, Ajax.org B.V.
  5. * All rights reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions are met:
  9. * * Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * * Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. * * Neither the name of Ajax.org B.V. nor the
  15. * names of its contributors may be used to endorse or promote products
  16. * derived from this software without specific prior written permission.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  19. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  20. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  21. * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
  22. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  23. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  24. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  25. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  26. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  27. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  28. *
  29. * ***** END LICENSE BLOCK ***** */
  30. define(function(require, exports, module) {
  31. "use strict";
  32. var oop = require("../lib/oop");
  33. var Mirror = require("../worker/mirror").Mirror;
  34. var lint = require("./javascript/jshint").JSHINT;
  35. function startRegex(arr) {
  36. return RegExp("^(" + arr.join("|") + ")");
  37. }
  38. var disabledWarningsRe = startRegex([
  39. "Bad for in variable '(.+)'.",
  40. 'Missing "use strict"'
  41. ]);
  42. var errorsRe = startRegex([
  43. "Unexpected",
  44. "Expected ",
  45. "Confusing (plus|minus)",
  46. "\\{a\\} unterminated regular expression",
  47. "Unclosed ",
  48. "Unmatched ",
  49. "Unbegun comment",
  50. "Bad invocation",
  51. "Missing space after",
  52. "Missing operator at"
  53. ]);
  54. var infoRe = startRegex([
  55. "Expected an assignment",
  56. "Bad escapement of EOL",
  57. "Unexpected comma",
  58. "Unexpected space",
  59. "Missing radix parameter.",
  60. "A leading decimal point can",
  61. "\\['{a}'\\] is better written in dot notation.",
  62. "'{a}' used out of scope"
  63. ]);
  64. var JavaScriptWorker = exports.JavaScriptWorker = function(sender) {
  65. Mirror.call(this, sender);
  66. this.setTimeout(500);
  67. this.setOptions();
  68. };
  69. oop.inherits(JavaScriptWorker, Mirror);
  70. (function() {
  71. this.setOptions = function(options) {
  72. this.options = options || {
  73. // undef: true,
  74. // unused: true,
  75. esnext: true,
  76. moz: true,
  77. devel: true,
  78. browser: true,
  79. node: true,
  80. laxcomma: true,
  81. laxbreak: true,
  82. lastsemic: true,
  83. onevar: false,
  84. passfail: false,
  85. maxerr: 100,
  86. expr: true,
  87. multistr: true,
  88. globalstrict: true
  89. };
  90. this.doc.getValue() && this.deferredUpdate.schedule(100);
  91. };
  92. this.changeOptions = function(newOptions) {
  93. oop.mixin(this.options, newOptions);
  94. this.doc.getValue() && this.deferredUpdate.schedule(100);
  95. };
  96. this.isValidJS = function(str) {
  97. try {
  98. // evaluated code can only create variables in this function
  99. eval("throw 0;" + str);
  100. } catch(e) {
  101. if (e === 0)
  102. return true;
  103. }
  104. return false
  105. };
  106. this.onUpdate = function() {
  107. var value = this.doc.getValue();
  108. value = value.replace(/^#!.*\n/, "\n");
  109. if (!value)
  110. return this.sender.emit("annotate", []);
  111. var errors = [];
  112. // jshint reports many false errors
  113. // report them as error only if code is actually invalid
  114. var maxErrorLevel = this.isValidJS(value) ? "warning" : "error";
  115. // var start = new Date();
  116. lint(value, this.options);
  117. var results = lint.errors;
  118. var errorAdded = false
  119. for (var i = 0; i < results.length; i++) {
  120. var error = results[i];
  121. if (!error)
  122. continue;
  123. var raw = error.raw;
  124. var type = "warning";
  125. if (raw == "Missing semicolon.") {
  126. var str = error.evidence.substr(error.character);
  127. str = str.charAt(str.search(/\S/));
  128. if (maxErrorLevel == "error" && str && /[\w\d{(['"]/.test(str)) {
  129. error.reason = 'Missing ";" before statement';
  130. type = "error";
  131. } else {
  132. type = "info";
  133. }
  134. }
  135. else if (disabledWarningsRe.test(raw)) {
  136. continue;
  137. }
  138. else if (infoRe.test(raw)) {
  139. type = "info"
  140. }
  141. else if (errorsRe.test(raw)) {
  142. errorAdded = true;
  143. type = maxErrorLevel;
  144. }
  145. else if (raw == "'{a}' is not defined.") {
  146. type = "warning";
  147. }
  148. else if (raw == "'{a}' is defined but never used.") {
  149. type = "info";
  150. }
  151. errors.push({
  152. row: error.line-1,
  153. column: error.character-1,
  154. text: error.reason,
  155. type: type,
  156. raw: raw
  157. });
  158. if (errorAdded) {
  159. // break;
  160. }
  161. }
  162. // console.log("lint time: " + (new Date() - start));
  163. this.sender.emit("annotate", errors);
  164. };
  165. }).call(JavaScriptWorker.prototype);
  166. });