Live syntax-checking JavaScript with Emacs

There are quite some options for doing live syntax checks from within Emacs. A good one is using Steve Yegge’s relatively new js2-mode for javascript editing which has a javascript parser built in. But that is not what this blog post will be about.

The other option is to use flymake with some command line javascript syntax checker. Two possible syntax checkers are Mozilla’s stand alone SpiderMonkey interpreter “smjs” with the “-s” (strict) option and Douglas Crockford’s JsLint running under Rhino. There are reasons to use each of them:

  • SpiderMonkey is the javascript engine currently used in Firefox. So, if it can not parse your javascript, neither can Firefox.
  • JsLint does more than just syntax checking, it also checks for bad style and possible programming errors, like missing semicolons and braces, assignment in an if conditions. This can be good, but it’s also a hinderance when you’re working on code that was not written to make JsLint happy and you don’t want to refactor it. Furthermore, the style enforced by JsLint might differ from your programming style, as it says on the web page: “Warning! JSLint will hurt your feelings.”
    I, for instance, like to leave out the braces after an if statement if the executed block is itself just one statement – it takes up less space, and if I ever want to add to this block Emacs will indent the code correctly, so I won’t forget to add the braces afterwards. However, maybe JsLint is right, because you sometimes have to collaborate with people that don’t use Emacs – maybe I should do them the favor.

Setting up SpiderMonkey

On an Ubuntu system the stand alone SpiderMonkey interpreter is provided by the package “spidermonkey-bin”. SpiderMonkey has the problem that it is just the javascript engine, but does not include the DOM, and there is no global window object. So if your javascript code does more than just defining functions you need to do some mocking. This is fortunately very easy to do.

The code I wanted to check also installs event handlers with prototype’s Event.observe method, so I had to mock that, too:

// fake the global window object
var window = this;
var Event = { observe: function() {} };

You will most probably need to extend this for your code. Now you can do a syntax check from the command line like this:

smjs -s -e "(load '/path/to/mock.js')" file-to-check.js

Setting up JsLint

JsLint is itself written in javascript. To use it from the command line you need the javascript interpreter Rhino. It is, not surprisingly, provided on Ubuntu by the package “rhino”. JsLint for rhino is avaiable here. To check a javascript file with rhino, just call it like this:

rhino /path/to/jslint.js file-to-check.js

Integrating both into Emacs

The following code allows you to do live syntax checking from within Emacs with either SpiderMonkey or JsLint. You can switch between them using “C-c t”. The code uses a circular list structure to keep the list of available methods, just for the heck of it.

(setq flymake-js-method 'spidermonkey)
(defun flymake-js-toggle-method ()
  (let ((methods '#1=(spidermonkey jslint . #1#)))
    (setq flymake-js-method (cadr (memq flymake-js-method methods)))
(defun flymake-js-init ()
  (let* ((temp-file (flymake-init-create-temp-buffer-copy
         (local-file (file-relative-name
              (file-name-directory buffer-file-name))))
    (if (eq flymake-js-method 'spidermonkey)
        (list "smjs" (list "-s" "-e" (format "load('%s')" (expand-file-name "/path/to/mock.js")) local-file))
      (list "rhino" (list (expand-file-name "/path/to/jslint.js") local-file)))))
(eval-after-load "flymake"
     (add-to-list 'flymake-allowed-file-name-masks
                  '("\\.js\\(on\\)?$" flymake-js-init flymake-simple-cleanup flymake-get-real-file-name))
     (add-to-list 'flymake-err-line-patterns
                  '("^\\(.+\\)\:\\([0-9]+\\)\: \\(SyntaxError\:.+\\)\:$" 1 2 nil 3))
     (add-to-list 'flymake-err-line-patterns
                  '("^\\(.+\\)\:\\([0-9]+\\)\: \\(strict warning: trailing comma.+\\)\:$" 1 2 nil 3))
     (add-to-list 'flymake-err-line-patterns
                   '("^Lint at line \\([[:digit:]]+\\) character \\([[:digit:]]+\\): \\(.+\\)$" nil 1 2 3))))
(defun my-js-setup-flymake ()
  (flymake-mode 1)
  (local-set-key (kbd "C-c n") 'flymake-goto-next-error)
  (local-set-key (kbd "C-c p") 'flymake-goto-prev-error)
  (local-set-key (kbd "C-c t") 'flymake-js-toggle-method))
(add-hook 'javascript-mode-hook 'my-js-setup-flymake)

The result

And here is what it looks like with SpiderMonkey:

Emacs with flymake running spidermonkey

And here an example of some code and what opinion JsLint has about it:

Emacs with flymake running jslint

1 Comment

Comments are closed.