Continuous Code Validation using JSLint

Callbacks are often found in JavaScript code. Some say ‘They are inconvenient and make code harder to understand’. Actually, it is a matter of habit and JS code may be as readable and easy to understand as any other. Additionally, this approach of coding allow us to ‘release’ program flow. No function is waiting for another’s result. Everything goes like stream.
Few month ago there was buzz around Node.js: Google’s V8 JavaScript engine acting as server. Before that nobody thought about event-based programming on server side. Every I/O operation in Node.js is asynchronous (database queries, reading from file or fetching content of some webpage). These are all the time used in web applications, especially real-time ones. Besides, lightweight and high-performance Nginx server is using event model.
There is enough articles about Node.js functioning. Today, I’ll show how to create real application that is checking in continuous way if our code project in JSLint by Douglas Crockford. All with growl notifications.
Node.js installation
Firsty, download and unzip the newest version of Node.js from GitHub.
Sadly, Node.js doesn’t support Windows: you must use Virtual Machine.
If you’re on Mac OS x, Linux or FreeBSD type this into console:
> git clone http://github.com/ry/node.git
> cd node
> ./configure
> make
> sudo make install
It will install Node.js on your machine. Check if everything works:
> echo "require('sys').puts('Hello world');" > test.js
> node test.js
If you see Hello World message, well done.
Creating project
Growl integration is boring – we’ll use one of many modules for Node.js. We’ll also need JSLint and two icons to make notification beautiful.
mkdir grolint
cd grolint
wget http://www.jslint.com/jslint.js
wget http://github.com/visionmedia/node-growl/raw/master/lib/growl.js
wget -O no.png http://imgur.com/Jq7TC.png
wget -O ok.png http://i.imgur.com/uihIH.png
In Node.js external files are included using require() function that returns object of global functions and variables in included file. In fact that object is equal to the exports object in included file. So if we want use JSLINT function from jslint.js file, we have to add one line at the end:
echo "exports.check = JSLINT;" >> jslint.js
We’ll also use built-in sys, fs, path and child_process modules. Sys is responsible for I/O with console, fs is acronym of File System and child_process allows us to run other console applications (Growl in our case).
Let’s create grolint.js file and write some first lines:
var sys = require('sys'),
fs = require('fs'),
path = require('path'),
growl = require('growl'),
jslint = require('./jslint');
Note that if we include non-internal module, we add ./ at the beginning of the relative path and we don’t add “.js” at the end. You may check if everything’s OK: place this at end of file and run node grolint.js command:
sys.puts(sys.inspect(jslint));
You should see something like:
{ check:
{ [Function]
data: [Function]
, report: [Function]
, jslint: [Circular]
, edition: '2010-04-06'
}
}
Application body
Our application will do two things:
- At the beginning validate all .js files in current directory against JSLint
- Watch for changes in every mentioned file and validate continuously
The first thing is validating single file.
function validate(filename, callback) {
sys.print('Checking ' + filename.replace(__dirname + '/', '') + '... ');
fs.readFile(filename, 'utf8', function(err, file) {
callback(jslint.check(file.replace(/^\#\!.*/, '')));
});
}
We created function validate in which we call fs.readFile that asynchronously reads the entire contents of a file. Second argument is encoding – binary, ascii or utf8. Third function is callback – and that’s beauty of Node.js. In PHP we would wait for contents of the file. Here interpreter continues working and when the file is loaded it will be passed as argument to callback function.
JSlint.check checks given JavaScript source and returns true/false depending on whether it validates. If no, errors are stored in jslint.checks.errors array.
Now, we need callback function that tells developer whether and what’s wrong:
function status(ok) {
if(ok) {
sys.puts("all right");
} else {
var errors = jslint.check.errors;
sys.puts(errors.length + ' errors');
for (var i = 0; i < errors.length; i += 1) {
if (errors[i]) {
sys.puts(' ' + errors[i].line + ': ' + errors[i].reason);
}
}
}
}
We want also similar function but with growl notifications. It will alert developer if something’s wrong in saved file:
function status_and_growl(ok) {
if(!ok) {
growl.notify(jslint.check.errors.length + ' errors (check console)');
}
status(ok);
}
Next. Notice we want to process every .js file in current directory and subdirectories. To accomplish that, we need function that walks a directory recursively and call specific function on each JavaScript file. Here’s source:
function walk(filename, callback){
fs.stat(filename, function(err, stats) {
if(stats.isFile() && filename.match(/\.js$/)) {
// Filename - do callback
callback(filename);
} else if(stats.isDirectory()) {
// Directory - walk recursive
fs.readdir(filename, function(err, files) {
for(var i = 0; i < files.length; i++) {
walk(filename + '/' + files[i], callback);
}
});
}
});
}
fs.stat checks stats (e.g. type or size) and passes it to callback function. If given filename is actually directory, we iterate through all files and recursively call function itself. If filename is JavaScript file, we pass it to callback function (in out case it will be validate).
Now we have all needed functions. What remains is call walk function on current directory (stored in predefined __directory variable) and use fs.watchFile function which watch for changes in particular file:
walk(__dirname, function(filename) {
// Check each file at the beginning
validate(filename, status);
// Watch every JS file for changes
fs.watchFile(filename, function(curr, prev) {
if(curr !== prev) {
validate(filename, status_and_growl);
}
});
});
There are two arguments in watchFile’s callback function: current and previous modification time. Why curr !== prev? This is a documentation bug, watchFile also triggers when a file is accessed, not just when it’s changed. We need to test modification time.
That’s it. Run code with “node grolint.js” and enjoy. You may optionally add grolint directory to PATH for further use.
You may find whole code here.
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
June 15, 2010 in Guides, JavaScript, Programming, Server Side | View Comments
-
Jakub Kułak
-
Robak Naziemny
-
Indrit
-
Datalion
-
Erik Giberti
-
Philippe Rathé







