.

Tags:

Due to the nature of the language, it is possible to construct JavaScript code that contains syntax errors which do not get detected until it is quite late. Yes, everyone should be using a smart editor or an intelligent IDE or a thorough linter or any other fancy tools, but an engineer is just human and mistakes happen all the time. I have seen such a blunder coming from experienced JavaScript developers, even those who are involved with many popular libraries. How do we prevent this?

Fortunately, it is rather easy to craft a command-line syntax validator once we have a modern JavaScript parser. You probably have seen the online version of Esprima-based validator when I blogged about checking strict mode conformance. While that online validator is useful for a quick verification of some code fragment, it is not optimal for any programmatic verification. Look no more! With the 1.0 version of Esprima some weeks ago, a simple-but-useful validator is included. It’s called (surprisingly) esvalidate.

If you are using Node.js, getting it is as easy as:

sudo npm install -g esprima

Now you can validate any JavaScript source files:

esvalidate foo.js bar.js baz*.js

If your files are syntatically valid, checking few megabytes of source should be completed in a second. Thanks to Google V8, Esprima under Node.js is really really fast.

Say you don’t like to depend on Node.js, no need to worry since you can also use the ubiquitous Java. The trick is to leverage Mozilla Rhino. The setup is rather simple; place the three files, js.jar from Rhino, esprima.js and esvalidate.js, all in the same directory. After than, run the validator as follows:

java -jar js.jar bin/esvalidate.js foo.js bar.js baz*.js

The above technique should work on Windows, Linux, and OS X. Hate to launch Java that way? Create a shell script or a batch file which wraps it. On Mac OS X, this is even easier since Rhino installation via Homebrew already prepared the wrapper /usr/local/bin/rhino and the above invocation is therefore simplified to:

rhino esvalidate.jsw foo.js bar.js baz*.js

Are you curious about the speed? Even though we have the overhead of running via Rhino on a JVM, the entire process is typically very fast. I measured the duration of validating three.js source (that’s 36K lines, total 800 KB) on a fairly modern laptop, it took just about 5 seconds. For a huge source file reaching over 5.5 MB, the validation was slowed down to around 20 seconds. Also, future version of Esprima will have some interesting tweaks to speed-up this particular use case. Thus, unless you write GB of JavaScript, expect the validation cost to be quite reasonable.

Note that a validator is slightly different than a linter. If you use some of the famous linter for JavaScript (JSLint or JSHint), you know that they are pedantic (to a certain extent) about the coding style. This validator does not care about style since its purpose is only to check for syntax errors. Thus, it is also perfect to use it with generated files as the result of minification or compilation (CoffeeScript, Dart, TypeScript, etc).

If you use Vim, you can set esvalidate as the makeprg for JavaScript files, rather easy via after/ftplugin. Launching make (better done through a shortcut) will inspect the validity of the edited file. Via the quickfix window, you can view the result and jump to any particular syntax problem.

I’m sure it is possible to integrate the validator with other popular editors such as Emacs, TextMate, or Sublime Text. Update: Sublime Text package for the validator is now available, see github.com/duereg/sublime-jsvalidate.

Executing esvalidate manually is annoying. We can take advantage of any preflight check mechanism of modern version control systems, for example see my previous blog post on Git pre-commit hook and smoke testing. Here is an example of the hook script. Every JavaScript file which has been touched since the previous check-in will be validated. If one of them fails the check, your commit will be aborted immediately.

files=$(git diff-index --name-only HEAD | grep -P '\.js$')
for file in $files; do
  esvalidate $file
  if [ $? -eq 1 ]; then
    echo "Syntax error: $file"
    exit 1
  fi
done

Are you using Grunt for your build workflow? Look no more, install grunt-jsvalidate (which I created some time) and you have a new task jsvalidate which does the validation just like the above. Of course, under the hook it also uses Esprima.

Running a continuous integration system? There is a support for JUnit XML format as the output. This means, the validation report can be consumed easily by e.g. Jenkins or TeamCity.

With these multiple layers of defense during editing, code check-in, build, and continuous integration, hopefully the chance of making a stupid mistake is significantly reduced. How would you plan to guard yourself with a syntax validator?

  • mseeley

    Great tool and examples. Immediately useful. Thanks. :)

  • Jeff M

    I don’t see any benefit over JSHint. Sorry. :(

  • Keith

    Excellent tool & great idea – I’ll be using this to validate my Jasmine unit test files. With Jasmine any unit test files which have an error in the JavaScript syntax simply don’t run and don’t get flagged as there being an error.

  • uolot

    I subscribed to your RSS just yesterday, so please forgive me if you already answered this question in one of your previous posts – what’s your Vim colorscheme?

    • http://ariya.ofilabs.com/ Ariya Hidayat

      It’s molokai.

  • http://twitter.com/arthurakay Arthur Kay

    Your examples show you using “esvalidate” from a shell script – is there any way to use this utility from within Node.js itself?

    For example, if I require the esprima module within my own code can I use “esvalidate” in some way?

    • http://ariya.ofilabs.com/ Ariya Hidayat

      It should be dead easy. Have you seen esvalidate.js code? :)

      • http://twitter.com/arthurakay Arthur Kay

        Hm, is that under /bin? I had not noticed till just now :-)

  • http://twitter.com/jefftschwartz Jeff Schwartz

    Ariya, perhaps you can dedicate a blog article describing the advantages of using Esprima over jslint/jshint. I’d personally find that very interesting as I’d guess others might also.

    • http://ariya.ofilabs.com/ Ariya Hidayat

      But they are two different things (Esprima is only a parser). Beside, I’ve talked and spoken about this topic already, see the Talks page in this blog.

  • isao

    great post, thanks! btw the pre-commit script breaks on deleted files.. you should add –diff-filter=ACM to `git diff-index`.