Using JSLint from Ant

[This originally appeared on my dev2dev blog 16-Nov-2007]
Here are instructions for using JSLint from Ant to check your JavaScript for common potential problems.

There is an online version of JSLint, which is cool, but we don’t build our software by pasting it into online forms right? It is natural to want to use JSLint from Ant assuming you’re in the Java world. The JSLint documentation gives pretty good motivation for why you would want to use JSLint as part of your build.

Besides the web version JSLint comes in WSH or Rhino command line versions. I could exec a Rhino command line from Ant but I wanted something a little more integrated. I wanted to be able to do something like this:

<jslint options="{passfail: false, browser: true}">
    <fileset dir="${src.dir}">
        <include name="javascript/*.js"/>
        <include name="lib/js/*.js"/>
    </fileset>
</jslint>

I looked around for an existing ant task. There is a Java command line version jslint4java that has an ant task. I have not tried it so I can’t say anything about how it works.

It seemed to me that since JSLint is written in JavaScript that it should be possible to use it with an ant scriptdef tag. Here is how to do it.

  1. Download fulljslint.js and make a copy of it called jslintant.js.
  2. Depending on your version of ant you may need newer versions of Rhino and BSF. I used js.jar from Rhino 1.6R7 and BSF 2.4.0.
  3. Edit jslintant.js and add these lines to the very bottom of the file.
    importClass(java.io.File);
    importClass(Packages.org.apache.tools.ant.util.FileUtils);
    importClass(java.io.FileReader);
    
    var options = attributes.get("options")
    var fileset;
    var ds;
    var srcFiles;
    var jsfile;
    
    project.log("Attribute options = " + options);
    eval("options = " + options + ";");
    
    if (elements.get("fileset").size() > 0) {
        // should only be one fileset
        fileset = elements.get("fileset").get(0);
    
        ds = fileset.getDirectoryScanner(project);
        srcFiles = ds.getIncludedFiles();
    
        // for each srcFile
        for (i = 0; i < srcFiles.length; i++) {
            jsfile = new File(fileset.getDir(project), srcFiles[i]);
            checkFile(jsfile);
        }
    }
    
    function checkFile(file, options) {
        // read the file into a string and make it a real 
        // JavaScript string!
        var reader = new FileReader(file);
        // readFully returns java.lang.String
        // new String makes it a java String object
        var input = new String(FileUtils.readFully(reader)); 
        // this makes the type string, which is important
        // because JSLINT assumes that input is an array 
        // if it is not typeof string.
        input = input.toString();
        if (!input) {
            print("jslint: Couldn't open file '" + file.toString() + "'.");
            return;
        }
        if (!JSLINT(input, options)) {
            project.log("jslint: Problems found in " + file.toString());
            for (var i = 0; i < JSLINT.errors.length; i += 1) {
                var e = JSLINT.errors[i];
                if (e) {
                    project.log('Lint at line ' + (e.line + 1) + ' character ' +
                            (e.character + 1) + ': ' + e.reason);
                    project.log((e.evidence || '').
                            replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"));
                    project.log('');
                }
            }
        } else {
            project.log("jslint: No problems found in " + file.toString());
        }
    }
  4. Add a scriptdef element to your ant target as follows.
    <scriptdef name="jslint" 
            src="${path_to_script}/jslintant.js" 
            language="javascript">
        <attribute name="options"/>
        <element name="fileset" type="fileset"/>
    </scriptdef>

Now you can use the jslint task as shown above.

5 thoughts on “Using JSLint from Ant

  1. I’m glad it worked for you Neil.
    There is a bug in the above code, hopefully you and others have caught and fixed it.
    In the call to checkFile I forgot to pass in options.

    To get the build to fail you should count the total number of errors and then at the end of the loop

    if (numerrors > 0) {
    throw BuildException(numerrors + “jslint errors”);
    }
    I think the above works but have not tried it. I just print out the total number of errors.

  2. Hi John

    thanks for this, worked like a charm straight out of the box. One question: how would I get the build to fail on a Lint fail?

    Neil

  3. [Comments from original post]
    *
    I’ve recently created a project at google which uses the above code to incorporate JSLint into a JS testing framework. Check it out at Rhinounit I believe it is a very clean, and fast, way of writing good JS unit tests.

    Posted by: tiestvilee on May 13, 2008 at 4:19 AM

    *
    I don’t know if the Java version makes a difference. I am using Java 1.5 or 1.6, Ant 1.6.5, Commons logging 1.1, Rhino 1.6R7 and BSF 2.4.0.

    Posted by: jsnyders on April 1, 2008 at 11:57 AM

    *
    does this require java 1.5 to work? the shop where i work is still on 1.4.2 — i keep getting the “Unable to load script engine manager” error…

    Posted by: pyroblue on April 1, 2008 at 11:46 AM

    *
    You will also need commons logging jar. I found version 1.1 to work (commons-logging-1.1.jar)

    Posted by: jsnyders on November 17, 2007 at 7:14 PM

Comments are closed.