JSHint Changed Files Only

Do you use a linter like JSHint for your JavaScript projects? Has running jshint to lint your entire project become slow? Do you use git to version your project? If so, this script will solve your slow linting problems. It uses git to detect which files have been changed and only lints those files rather than your entire project. This results in a much faster linting.

#!/bin/bash
#
# Lints all files that have changed

# check if we are in a git repo
isInGitMsg="$(git rev-parse --is-inside-work-tree)"  
retval=$?

if [ "$isInGitMsg" != "true" ]  
then  
  echo -n "$isInGitMsg" >&2
  exit $retval
fi;

# get the files that we should lint
files="$(  
  {
    # NOTE: the file paths returned are relative to the git root despite the current working directory
    # list all files that have changed (but not staged)
    git diff --name-only --diff-filter=ACMRTUXB;

    # list all files that have changed (and staged)
    git diff --name-only --diff-filter=ACMRTUXB --cached;

    # list all untracked (new) files
    git ls-files --others --exclude-standard;
  } |
    # only lint files that end with .js
    grep '\.js\$' |
    # remove duplicate files
    sort -u
)"

if [ -z "$files" ]  
then  
  exit 0
fi

# cd up to the git root
# example: if we are in {gitRoot}/fu/bar/ then cd ../../
cd "$(git rev-parse --show-cdup)"

# get the current working directory (now git root) absolute path
cwd="$(pwd)"

# escape sed special chars and add trailing slash
# we will use this with sed below
sedCWD="$(echo $cwd | sed -e 's/\\/\\\\/g' -e 's/\//\\\//g' -e 's/&/\\\&/g')\/"


# lint files
# this assumes you have a .jshintrc config file at the git root
jshint --config .jshintrc $files |  
  # jshint displays the absolute path for each file which is annoying
  # lets trim that so they are relative to the git root
  sed "s/^$sedCWD//"

# use the return value of the jshint command (first command in the pipeline)
exit ${PIPESTATUS[0]}  

I saved this as gshint and added it to my path env variable. Now I can just type gshint instead of jshint and I get much faster linting. Don't forget to make it exectuable with chmod +x gshint.

You can also turn this code into a git pre-commit hook to ensure all code is linted before commiting. I describe how here.

Mike Moore

Read more posts by this author.

Austin, TX yo1.dog
comments powered by Disqus