SonarQube JavaScript plugin: why compete with JSLint and JSHint ?

This question has been raised several times on the Sonar mailing lists. Indeed since version 1.0, the SonarQube JavaScript plugin hasn’t relied on external rule engines like JSLint or JSHint. Like most SonarQube rule engines, the one for JavaScript is now fully based on our own open source code analysis technology: SSLR.

So why did we move away from JSLint or JSHint, which are both highly used and pretty good? In fact, the question is the same for most SonarQube language plugins: why move away from Checkstyle (Java), PMD(Java), CPPCheck(C/C++), FlexPMD(Flex), and so on? The choice doesn’t relate to the quality of those rule engines. It is only motivated by a long term strategy based on the following observations :

  • KISS principle: Language plugins should not require any third party tool installation/configuration/execution, which can be cumbersome and error-prone.
  • Speed: Executing multiple rule engines, such as JSLint, JSHint, and the JavaScript SonarQube rule engine is a kind of duplication which can lead to much longer analysis times.
  • Reactivity: Fixing a bug in a rule should be a non-event, and should not depend on a third party tool’s development lifecycle.
  • Stability: Regardless of the quality of the third party tools involved, we have to view a non-native integration based on input files and forked processes as unstable. There are just too many unknowns to treat it otherwise: the version, the installation, and the interactions between the tool and the flavor and version of the OS.

Obviously, basing all language rule engines on the same technology (the SonarQube-native SSLR) is the best way for SonarSource to leverage our development capability.

So coming back to the JavaScript plugin, the current version embeds 61 rules, and just to make you eager to test the plugin here are few of them:

Avoid variable shadowing

Overriding a variable declared in an outer scope might highly impact the readability and so maintainability of a piece of code.
The following code snippet illustrates this rule :

show: function(point, element) {
  if (!this.drops.length) return;
  var drop, affected = [];
  this.drops.each( function(drop) { // Non-Compliant as the 'drop' parameter is not the one defined one line before even if it looks like
    if(Droppables.isAffected(point, element, drop))
      affected.push(drop);
  });

See some examples of issues on real life projects.

Declare variables before usage

One of the sources of most confusion for JavaScript beginners is scoping. The reason scoping is so confusing in JavaScript is because it looks like a C-family language but doesn’t behave the same way. Indeed C, and the rest of the C family, has block-level scope. When control enters a block, such as a if statement, new variables can be declared within that scope, without affecting the outer scope. This is not the case in JavaScript.

The following code snippet illustrates this rule :

var x = 1;

function fun(){
  print(x); // Non-Compliant as x is declared later in the same scope
  if(something) {
    var x = 42; // Declaration
  }
}

fun(); // Unexpectedly Print "undefined" and not "1"

Whereas the following one is correct:

var x = 1;

function fun() {
  print(x); // 1
  if (something) {
    x = 42;
  }
}

fun(); // Print 1

Avoid use of == and != in favor of === and !==

The == and != operators do type coercion before comparing. This is bad because it causes ' \t\r\n' == 0 to be true. This can mask type errors. It is best to not use == and != and to always use the more reliable === and !== operators instead.

“eval” and “arguments” must not be bound or assigned

In JavaScript, eval is used to add or remove bindings and to change binding values. arguments is used to access function arguments through indexed properties. As a consequence, those 2 names eval and arguments should not be bound or assigned as it would overwrite the original definition of those 2 elements.

What’s more, using those 2 names to assign or bind will generate an error in JavaScript strict mode code.

The following code snippet illustrates cases that will generate violations (changing the names turns the different non-compliant cases into compliant cases):

eval = 17; // Non-Compliant
arguments++; // Non-Compliant
++eval; // Non-Compliant
var obj = { set p(arguments) { } }; // Non-Compliant
var eval; // Non-Compliant
try { } catch (arguments) { } // Non-Compliant
function x(eval) { } // Non-Compliant
function arguments() { } // Non-Compliant
var y = function eval() { }; // Non-Compliant
var f = new Function("arguments", "return 17;"); // Non-Compliant

Avoid definition of functions inside loops

Defining functions inside of loops can lead to bugs such as this one:

var funs = [];
for (var i = 0; i < 13; i++) {
  funs[i] = function() { // Non-Complian
    return i;
  };
}
print(funs[0]()); // 13 instead of 0
print(funs[1]()); // 13 instead of 1
print(funs[2]()); // 13 instead of 2
print(funs[3]()); // 13 instead of 3
...

To sum it up, the JSLint and JSHint are good JavaScript coding rules engines, but they don't suit our long-term needs. Instead, we're committing to compete strongly with them.

© 2008-2013, SonarSource S.A, Switzerland. All content is copyright protected. SONARQUBE and SONARSOURCE are
trademarks of SonarSource SA. All other trademarks and copyrights are the property of their respective owners. All rights are expressly reserved.