Bill Lovett

Command Line JavaScript Validation

Let's make JSLint easier to run by calling it from the command line via wrapper script. Let's also incorporate Google's Closure Linter while we're at it for double the fun.

Here's the finished product. Read on for further details.

Why?

Linters make your code look better to machines as well as humans. They point out stupid typos and petty errors. They enforce best practices and consistent style, and prevent you from lapsing just because you were in a hurry. Best of all, they let you know whether you're really as good as you think you are.

Scenarios for Running JSLint

There are lots of ways to incorporate JSLint into your workflow, but none were as low-effort as I wanted. Flymake for JavaScript seemed promising at first, but I decided that on-the-fly checking would be annoying.

Maybe something service-esque? There's Lintnode, but its components no longer work together. How about running JSLint's web interface locally, scripting a POST request and scraping the result? That's all wrong. JSLint needs a JavaScript runtime--the checking happens client-side. There are no obvious browser automation possibilities here, and copy-paste is not desirable.

Maybe Spidermonkey? There's a workaround for its inability to read files, but I'm not keen on using a modified version of JSLint.

That leaves Rhino. It's convered by one of the "official" editions of JSLint, but it's not necessarily a speed demon. I can live with that.

The Setup

If you use JSLint straight from the command line, the results won't be pretty.

 rhino jslint.js functions.js
 
 ...
 
 Lint at line 8 character 13: 'jQuery' is not defined.
 

References to third-party libraries will throw spurious errors because JSLint hasn't been told about them. We need to define some global variables to prevent that confusion. We also need a flexible way to specify JSLint's configuration options.

These things could go directly into the files you will lint, but that's extraneous clutter. The approach I've taken instead is:

  • Define a standard set of options in the wrapper script.
  • Pass in any additional globals as an argument.
  • Prepend both to a copy of the file being linted.
  • Stop after the first error

I find that going through errors one at a time is easier than seeing everything at once.

The Settings

I started with JSLint's "Good Parts" options. I disabled "Strict white space" (white) because of a difference in opinion with Closure Linter I'll describe in a bit. As mentioned above, "Stop on first error" (passfail) is enabled. So is "Assume a browser" (browser).

Adding Closure Linter

Closure Linter is already suited to running from the command line, so not much effort is involved here. I'm running it after JSLint, but the order could certainly be reversed.

JSLint and Closure Linter disagree about whitespace after "function" and the subsequent left parentheses. JSLint wants it, Closure Linter doesn't. I decided to go with the latter (hence the "Strict white space" config change mentioned above). I'm sure there are epic arguments both pro and con on both sides, but this is minutiae.

How It Looks

Example 1:

 $ validate-js functions.js
 
 # JSLint
 ############################################################
 No problems found.
 
 # Closure Linter
 ############################################################
 Line 5, E:0220: No docs found for member 'BB.video'
 Line 25, E:0220: No docs found for member 'BB.rsvp'
 Line 79, E:0110: Line too long (103 characters).
 Line 85, E:0220: No docs found for member 'BB.slideshow'
 

Example 2:

 $ validate-js functions.js
 
 # JSLint
 ############################################################
 Line 1 character 1: Missing "use strict" statement.
 var GK = function() {
 
 Stopping (0% scanned).
 
 
 
 # Closure Linter
 ############################################################
 Line 7, E:0131: Single-quoted string preferred over double-quoted string.
 Line 7, E:0131: Single-quoted string preferred over double-quoted string.
 Line 8, E:0131: Single-quoted string preferred over double-quoted string.
 Line 8, E:0131: Single-quoted string preferred over double-quoted string.
 Line 9, E:0131: Single-quoted string preferred over double-quoted string.
 Line 9, E:0131: Single-quoted string preferred over double-quoted string.
 Line 9, E:0110: Line too long (82 characters).
 Line 36, E:0131: Single-quoted string preferred over double-quoted string.
 Line 36, E:0131: Single-quoted string preferred over double-quoted string.
 Line 37, E:0131: Single-quoted string preferred over double-quoted string.
 Line 38, E:0131: Single-quoted string preferred over double-quoted string.
 Line 39, E:0131: Single-quoted string preferred over double-quoted string.
 Line 42, E:0002: Missing space before "="
 Line 42, E:0002: Missing space after "="