A Comparison of JavaScript Linting Tools

article

#19

I can change tabstop to 2, 4, 8, anything, and the code will always indent the same. You only use tabs for indentation. If you follow a pattern where you use it only for indentation and nothing else, there is no problem.

What about the other case I mentioned?

Yeah that's true. I was referring to the lack of it in the tool itself, so you need another tool to complement it for something that others have out of the box. Of course you can always slap something else on top to fix things in many cases.

Considering the argumentation for JSLint seemed to be it doesn't require configuration, this seems to defeat it.


#20

On your particular setup it will indent the same. When your code is shared with other people, that's where problems can occur. What works well for you at a tab stop of 2 can be a big problem where someone else has a tab stop they can't change of 8.

The problems of working with other people can be hard to deal with, and commonly requires a solution of setting unreasonable standards.

I have no wish to misrepresent you, so please clarify which case that is that you mean.

You seem to be misunderstanding what's happening here, for we are not two Titans holding a grand debate. Instead, I am working on finding solutions and answers for you. So saying, what else can we help you with here?


#21

Here's a sample with tabstop 2:

function foo() {
  hello();

  if(foo) {
    bar();
  }
}

Here's a sample with tabstop 4:

function foo() {
    hello();

    if(foo) {
        bar();
    }
}

Here's a sample with tabstop 8

function foo() {
        hello();

        if(foo) {
                bar();
        }
}

I don't see the problem.

The second case was extra spaces around an argument name.


#22

The problem so far as I understand it is that deeply nested code at a tab stop of 2 will be much harder to work with at a tab stop of 8.

Now I realise that deeply nested code is a code smell that we all should work on lessening, but that simple situation where the same exact code has widely varying aspects of usability depending on which particular tab stops you choose to use, was a problem to be resolved.

What would you propose to do to resolve such a problem?

Another issue is in terms of how can you visually tell if tabs or spaces are causing a problem? Some people resort to using visual tabs and spaces to help resolve such problem.

Other issues come in displaying code on a web page, where tabs can be tricker to nail down in to place.

It seems that tabs are responsible for the greater majority of technical problems, and that removing tabs removes those problems. That is the path that Crockford has been taking, to remove that which is causing problems. It's not a popular path to take, but at times the right path is not the popular one.

What do you wish to know about this?

My understanding is that when coders argue about using one or two spaces, that no common ground can be found so a standard has to be put in place to prevent such arguments.

The need for a common ground is occurs when people attempt to work together on the same code. When someone checks out code and updates it, with their own personal spin on the formatting applied, that ends up screwing up any form of change control within the code.

Remove the cause of the problem and set a coding standard, and things are sailing on an even keel once again.

We want to be making progress on the code. Bickering about how many spaces are to be used to separate terms impedes any such progress.


#23

If someone really really wants to use a tabstop of 8, then I think it's their problem. But that is certainly something to think about.

tab-size CSS property works well unless you're using a wonky browser (read: IE)

Claims were made that all the rules in JSLint have an objective benefit. I agree there is an objective benefit from a codebase having the same style used for spacing, but the specific way of spacing enforced by JSLint is equally subjective as any other variation.


#24

Not really IEs fault. IE11 was only introduced in OCT 2011 and that's basically when tab-size was introduced.

IE9-11 aren't terrible CSS browsers frowning .


#25

Yes indeed, and sometimes people just can't help the type of software they're stuck with.

Okay, let's get away from subjective claims and towards the more objective nitty gritty. What in particular about a the spacing style seems to you to be subjective? An example of code that demonstrates the difference and your preference will be appreciated too.

Such as for example:

var a = (2 + 3) * 4;

vs

var a = ( 2 + 3 ) * 4;

#26

Well, looking at for example what you just posted. Is one of the ways you showed objectively better than the other?


#27

There are three main styles of white-space separation that are used. I'll use a haversine formula for the example, so that a combination of functions, numbers, and variables can be seen.

if(!Math.TAU){Math.TAU=Math.PI*2;}
function degreesToRadians(deg){return deg*Math.TAU/360;}
function haversine(lat1,lon1,lat2,lon2){
    var earthRadius=6372.8,//km
        dLat=degreesToRadians(lat2)-degreesToRadians(lat1),
        dLon=degreesToRadians(lon2)-degreesToRadians(lon1),
        a=Math.pow(Math.sin(dLat/2),2)+Math.pow(Math.sin(dLon/2),2)*Math.cos(lat1)*Math.cos(lat2),
        c=2*Math.asin(Math.sqrt(a));
    return earthRadius*c;
}

The above is a style that many consider to be too cramped to easily make out names and details when they are used within the code.

if (!Math.TAU) {
    Math.TAU = Math.PI * 2;
}
function degreesToRadians(deg) {
    return deg * Math.TAU / 360;
}
function haversine(lat1, lon1, lat2, lon2) {
    var earthRadius = 6372.8, // km
        dLat = degreesToRadians(lat2) - degreesToRadians(lat1),
        dLon = degreesToRadians(lon2) - degreesToRadians(lon1),
        a = Math.pow(Math.sin(dLat / 2), 2) + Math.pow(Math.sin(dLon / 2), 2) * Math.cos(lat1) * Math.cos(lat2),
        c = 2 * Math.asin(Math.sqrt(a));

    return earthRadius * c;
}

The above tends to be the default spacing style, primarily due to it being used in the ECMASCRIPT specifications. Also, the spaces between operands act as punctuation, helping you to more easily understand what's going on.

if ( !Math.TAU ) {
    Math.TAU = Math.PI * 2;
}

function degreesToRadians ( deg ) {
    return deg * Math.TAU / 360;
}

function haversine ( lat1, lon1, lat2, lon2 ) {
    var earthRadius = 6372.8, // km
        dLat = degreesToRadians( lat2 ) - degreesToRadians( lat1 ),
        dLon = degreesToRadians( lon2 ) - degreesToRadians( lon1 ),
        a = Math.pow( Math.sin( dLat / 2 ), 2 ) + Math.pow( Math.sin( dLon / 2 ), 2 ) * Math.cos( lat1 ) * Math.cos( lat2 ),
        c = 2 * Math.asin( Math.sqrt( a ) );
    
    return earthRadius * c;
}

The above tends to result in lines of code that are around 10% longer in length, and seems to make it trickier to interpret the operations being performed. When all of the code is equally spread out it's more difficult to determine what's important.


#28

The last two are clearly better than the first. But whether the 2nd or 3rd is best is what's not so clear. You can say that the lines are 10% longer, but you could also say that especially when function calls are nested like Math.pow( Math.sin( dLat / 2 ), 2 ), it's easier to tell them apart.

Who can say for certain whether the length difference is significant, or whether the readability of nested calls is significant? Or whether it's actually more or less readable at all?

To make matters even more interesting, we could ask someone with dyslexia smile


#29

My understanding is that the criticism of tabs comes down to 1) alignment problems, and 2) editor problems.

Alignment problems because, for example, something like this is common:

(function () {
    // ...
    
    if (cond1
        cond2
        cond3) {
    }
    
    // ...
}());


If you're going to use tabs to indent and you still want this code to look correctly formatted for everyone else, then you need to take special care to use the right mixture of tabs and spaces.

(function () {
→// ...

→if (cond1
→••••cond2
→••••cond3) {
→}

→// ...
}());

Most people don't get this mixture right. Even some of the best programmers don't always get this right. I recall seeing alignment problems in the Linux kernel, for example.

And the other problem is editors, which I'm told sometimes replaces a file's indentation style to match the editor's configured style, so code commits end up with a lot of white space diffs.

In a perfect world, tabs would be the way to go. As the argument goes, everyone would get to indent to whatever width they prefer. But, unfortunately, a lot of human error creeps in, and tabs end up doing more harm than good.


On Our Radar: Show us your library, and other ways to win!
#30

Well let's compare the difference, with a simpler to examine situation involving parenthesis.

The question is: should an opening parenthesis always be followed by a space, and a closing parenthesis have a space just before it?

When there is no inter-parenthetical space involved, we have the following code:

function calc(a) {
    return (a + 3) * 4;
}

When there is a space involved, we end up with confusion in regard to the function parenthesis:

// air-gapped parenthesis
function calc ( a ) {
    return ( a + 3 ) * 4;
}

Do function parameters parenthesis behave the same as expression parenthesis? Or are they different?

// only air-gap expression parenthesis
function calc (a) {
    return ( a + 3 ) * 4;
}

Are the function names to be separated from the parenthesis too? They then become too easily confused with variables instead.

What happens when there are no function parenthesis?

// how to handle empty function parameters
function calc( ) {
    return ( 2 + 3 ) * 4;
}

Should the linter insist on a double space in the middle, one for each parenthesis, or just stick with a single space?

// a double space, one for each parenthesis
function calc(  ) {
    return ( 2 + 3 ) * 4;
}

Does it also mean that immediately invoked function expressions have to be spaced out too?

( function ( ) {
    ...
} ( ) );

Just how are such parenthesis spacing issues to be determined by a static linter, let along a human being?

There is a way around such quandaries, and that is to take the path of least confusion. That being to insist on no space on immediately inside of parenthesis.

function calc(a) {
    return (a + 3) * 4;
}

On a separate note, have you chosen a particular set of coding style standards to stick to? There are quite a number of them, which are nicely compared at https://github.com/Seravo/js-winning-style


#31

If you use gulp, I have a plugin that brings all 3 linting tools at once (jshint, jscs and eslint) so you don't have to install the separate plugins https://github.com/bahmutov/gulp-lint-everything


#32

JSCS does support custom rules via "plugins" https://github.com/jscs-dev/node-jscs/wiki/Plugin-API.


#33

I use eslint with Webstorm. There is a very cool plugin for integrating Eslint with intelliJ/Webstorm - https://plugins.jetbrains.com/plugin/7494?pr=phpStorm


#34

@mrjoelkemp we updated the article to reflect this point. Thank you.


#35

For ESLINT. "Some configuration required" is a cons?? Surely that's one of the its strongest points - that you can configure it to death.


#36

Thanks for pretty nice article.

But I'm not sure why you comparing linting tools with code style checker (JSCS).

I don't know a project which using JSCS without a linter. JSCS itself is not a linter, but a lint-like tool that checks your code style (but not report suspicious parts like undefined variables or other bad parts).

Linting for me is not the same as linting for you wink


#38

Because the "expert" that decided that the 's' in a switch statement needs to be vertically aligned with the 'c' in each case statement was clearly WRONG!

Can you cite any "JS rule" where an opening brace doesn't mandate indentation for the remainder of the closure?

I do not care about popular opinion, I want examples that don't pander to said erroneously-propagated rule.


#39

What does that have to do with whether you use tabs or spaces for the indentation?