code prettify

Friday 12 February 2016

Associating git hooks with js syntax check

This is a followup article from my previous post.


Here we will be using git pre-commit to check for syntax error while committing in JavaScript files.

We will need nodejs in our system. Please check https://nodejs.org/en/ for downloading and install steps.

Note: I am using ubuntu 14.04 for this setup.

Steps to add pre-commit JavaScript syntax check with git:

1. Use npm to install jslint package globally in your system.

https://www.npmjs.com/package/jslint

$ npm install -g jslint

This should globally install jslint in your system and can be referenced as below to check syntax error for any js file.

$ jslint sample.js

for (i = 0; i < 10; i++)
{
        sum += i;
}

Sample output from above command:
sample.js
 #1 'i' was used before it was defined.
    for (i = 0; i < 10; i++) // Line 1, Pos 6
 #2 'i' was used before it was defined.
    for (i = 0; i < 10; i++) // Line 1, Pos 13
 #3 'i' was used before it was defined.
    for (i = 0; i < 10; i++) // Line 1, Pos 21
 #4 Unexpected '++'.
    for (i = 0; i < 10; i++) // Line 1, Pos 22
 #5 Expected exactly one space between ')' and '{'.
    { // Line 2, Pos 1
 #6 Use spaces, not tabs.
    sum += i; // Line 3, Pos 1
 #7 Expected 'sum' at column 9, not column 2.
    sum += i; // Line 3, Pos 2
 #8 'i' was used before it was defined.
    sum += i; // Line 3, Pos 9
 #9 Expected '}' at column 5, not column 1.
    } // Line 4, Pos 1

Above info is quite informative and helpful to fix basic syntax errors, missing semi-colons, indentation etc.

Correcting the above errors to below code and running jslint again:

var i, sum = 0;

for (i = 0; i < 10; i = i + 1) {
    sum += i;
}

Output from jslint:

sample.js is OK.

Note: Please also refer rules and standards being followed by jslint for checking here. Makes a nice read. :)

2. Now that jslint is globally available, let us use it and create a pre-commit file.
I found below links which highlight the use of it in a script:

http://stackoverflow.com/questions/15703065/setup-pre-commit-hook-jshint
http://dev.venntro.com/2012/11/maintaining-consistent-javascript-with-jslint/

The only disadvantage I see in the script is that it only highlights passed and failed JavaScript files with names and does not specify the error in each.

So, I made a few changes to the script as below (highlighted in blue):

#!/bin/sh

files=$(git diff --cached --name-only --diff-filter=ACM | grep "\.js$")
if [ "$files" = "" ]; then
    exit 0
fi

pass=true

ERRORS_BUFFER=""

echo -e "\nValidating JavaScript:\n"

for file in ${files}; do
    result=$(jslint ${file} | grep "${file} is OK")
    if [ "$result" != "" ]; then
        echo -e "\t\033[32mJSLint Passed: ${file}\033[0m"
    else
        ERRORS=$(jslint ${file})
        ERRORS_BUFFER="$ERRORS_BUFFER\n$ERRORS"
        echo -e "\t\033[31mJSLint Failed: ${file}\033[0m"
        pass=false
    fi
done

echo -e "\nJavaScript validation complete\n"

if ! $pass; then
    echo -e "\033[41mCOMMIT FAILED:\033[0m Your commit contains files that should pass JSLint but do not. Please fix the JSLint errors and try again."
    echo -e $ERRORS_BUFFER
    echo 
    exit 1
else
    echo -e "\033[42mCOMMIT SUCCEEDED\033[0m\n"
fi

3. Save the above script in your git pre-commit file as below:

$ cd /project/directory/
$ vim .git/hooks/pre-commit

Paste the above content and save it. Then give execute permission to it.

$ chmod +x .git/hooks/pre-commit

And we are done and ready :)

Trying a sample case:

I have two js files named sample.js and another.js with below content:

sample.js:

var i = j;

for (key in names) {
    echo names[key];

}

another.js:

var i = []

Lets try to commit them:

$ git commit -m 'Error Commit' sample.js another.js

Below is the pre-commit check output:

Validating JavaScript:

JSLint Failed: sample.js
JSLint Failed: true.js

JavaScript validation complete

COMMIT FAILED: Your commit contains files that should pass JSLint but do not. Please fix the JSLint errors and try again.

 sample.js #1 'j' was used before it was defined. var i = j; // Line 1, Pos 9 #2 'key' was used before it was defined. for (key in names) { // Line 3, Pos 6 #3 Cannot read property 'kind' of undefined // Line 3, Pos 10

 true.js #1 Expected ';' and instead saw '(end)'. var i = [] // Line 1, Pos 11

The output can be formatted a little bit better to place each line error in a new line of its own. But this simple tool is pretty handy for checking js errors while committing :)

No comments:

Post a Comment