A Comparison of JavaScript Linting Tools

It shouldn’t be a matter of what you like - the idea of any LINT is to detect any usage that may cause problems. One thing about JSLint is that all of the rules it uses are there to detect something that has been known to cause issues is scripts. Each rule has a corresponding example of a script that crashed because it didn’t follow that rule.

Not all of them have anything to do with issues. Examples of rules that are purely stylistic:

  • Use spaces for indentation, not tabs
  • White-space between parameters, function foo( a ) is not allowed, where function foo(a) is.

Although these can actually be disabled using the --white flag, who knows what else it does, since it’s not documented anywhere.

But that defeats the purpose of not having to configure it, as you were saying. Plus, since JSLint doesn’t have a configuration file, you have to remember to use the correct configuration flags whenever you run it.

As a fun factoid, the tabs vs spaces rule was silently added without warnings to JSLint. What if you had written your code in a certain way, and the next day it was decided that you no longer can do it like that? It seems a bit problematic to me. Especially as Douglas is saying new should not be used anymore, and many large codebases use it extensively. What happens if JSLint suddenly decides to not allow it anymore, just like it decided with tabs?

1 Like

Who knows what else? We can all know as the code provides us with the details. Doing a search for the word white reveals all.

Line numbers (after Chrome pretty-print)
155 - allowed options
242 - expected at column
258 - use spaces, not tabs
318 - unexpected character
1005 - expected space (one space)
1012 - expected space (one space only)
1019 - unexpected space (no space)
1026 - unexpected space (no space only)
1031 - missing space
1043 - no comma space then to 1026
1054 - no semicolon space then to 1026
2614 - expect case at same column as switch

The following code examples are poor code, to demonstrate the different JSLint white space warnings that are triggered within the code.

Expected x at column

var x = true;
 if (x) {
    x = false;
}

Use spaces, not tabs

var x = true;
if (x) {
	x = false;
}

Unexpected character (spaces on blank line)

var x = true;
    
if (x) {
    x = false;
}

Expected space

var x = true;
if(x) {
    x = false;
}

Expected only one space

function example() {
    "use strict";
    return  '';
}

Unexpected space

var a = ( 1 + 2);

Unexpected space where only none should be

var a = -[0 , 1];

Missing space

var x = true;
if (x){
    x = false;
}

Expect case at same column as switch

var expr = "Oranges",
    msg;
switch (expr) {
    case "Oranges":
        msg = "Oranges are $0.59 a pound.";
        break;
    case "Apples":
        msg = "Apples are $0.32 a pound.";
        break;
    default:
        msg = "Sorry, we are out of " + expr + ".";
}

Also, there’s a handy jslinterrors site that can be handy too, which was only used to retrieve some suitable coding examples for common issues.

I don’t know about you but I would learn about why tabs cause such as issue compared with spaces, and proceed to resolve the problem which can be easily and rapidly done across all code-bases with the right tools.

The issue with tabs vs spaces is purely subjective. Dog people vs cat people. Vim vs Emacs. Same thing.

Yes, it is subjective and you’ll find that Crockford himself doesn’t mind which is used either, as long as it’s consistant.

The issue of tabs vs spaces only becomes a problem when you are coding with other developers, at which point there’s an issue of change control among the code as developers fight like a pack of squabbling cats for control over the code base to set their own personal preference, and waste time converting everything back and forth.

As such, some sort of standard must be set for harmony to return, and it just so happens that the spaces side of the camp is seen to have less potential problems than tabs.

If you just so happen to prefer to indent using tabs, then clearly you will have problems with jslint.

I don’t agree but let’s not derail this into a tabs vs spaces thing :slight_smile:

Anyway, the point about the tabs rule and the white space around arguments rule was to show that not every rule in JSLint has an objective reason behind it. I think it’s fine for a tool to set a default for such rules though, but in JSLint’s case, it’s not so easy to deactivate the rule because it doesn’t have a configuration file.

Every rule came about as a response to a widely-regarded issue. Are there any other rules on which you are puzzled about its objective nature? Perhaps we can shed some light for you on the rationale behind it.

What sort of config file did you have in mind?

my-special-jslint-config.js

/* jslint white:false */

Well I didn’t really see anything on what problems tabs cause, or what problems white space around argument names cause.

A global configuration. The example you give with the comment is local only to a single file, therefore not very practical in larger projects.

One of the reasons is:

There are also issues in regard to a consistant layout, and that the default tab stop size is just too large. While it’s possible for custom tab stops to be configured, it still doesn’t help to provide consistency in other places.

I hope that you are not just being difficult now, and trust that you really are interested in some answers here.

Sublime Text for example has config files for jslint, both default ones and custom user config files too.

There are also jslint configs for when using grunt, and other systems that can be used to customise it for your build process.

It depends on the editor you are using. The one I use has a configuration setting for how many spaces to convert tabs to. This means that regardless of whether I type spaces or use tabs the resultant files always contain spaces and never contain tabs.

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.

[quote=“jhartikainen, post:19, topic:114646”]
I can change tabstop to 2, 4, 8, anything, and the code will always indent the same. [/quote]

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?

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.

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.

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.

1 Like

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: .

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;

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

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.

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: