…as well as JSHint itself, of course.
We drew up a quick spreadsheet for evaluating the tools and came up with the following.
Licensing Does the license meet our requirements (and those of our customers, of course)?
Project health/adoption How healthy is the project? Is it on Github, and is it well maintained?
Completeness of configurations Does the tool cover all our use-cases for a linting tool?
Productivity (rule set creation / project setup) When creating a new project, is it difficult to create a matching ruleset? Does the tool come with a reasonable default rule set, or do you need to set up all the checks yourself?
Productivity (active software development) During active development, does the tool assist the developer in writing quality code, or does it bully you to the point where you’d rather abolish using a linting tool at all?
Quality of Documentation/Tutorials/Self Help How good is the project documentation? When the tool breaks the build with a certain error message, how difficult is it to find reliable information on the error in question (why does it occur, why is it a bad practice, how to fix it)?
Ability to integrate with existing projects Is it possible to integrate the linting tool in an existing projects without making changes to the project to comply to the rules?
Integration with build tool Is it possible to integrate the linting tool into your build chain to receive direct feedback?
ES6 support How well does the project support future versions of the language?
Pluggable Is it possible to extend the given rule set with custom checks?
The first tool we looked at was the already-familiar JSHint. We already knew what was bothering us about it:
Its hard to find the documentation for a certain error message. While the error messages itself are mostly self-explanatory, it can be somewhat difficult to find out how to deactivate or customize a certain rule. For example, http://jshint.com/docs/options/ JSHint has both ‘enforcing’ and ‘relaxing’ rules. While setting a ‘enforcing’ rule to true turns it on, setting a ‘relaxing’ rule to true deactivates it.
More often than not, using JSHint can be frustrating. For example, we had ‘maxdepth’ set to 3, meaning a maximum of three nested blocks of code was allowed. In case one of those blocks was a ‘for … in’ statement, JSHint would (correctly) complain that its body should be wrapped in an ‘if(obj.hasOwnProperty(key))’-check to filter out unwanted properties. However, doing so meant introducing another nested block, and if that pushed the total depth beyond ‘maxdepth’, JSHint would fail the build. The solution was usually to introduce private helper functions, which can make otherwise trivial code difficult to read (since you have to skip blocks of code).
- Being a fork of JSLint, JSHint has the same license containing the infamous JSLint License ‘Good, not evil’ statement. While we understand its humorous intent (and being a fairly social responsible company, we wholeheartedly support it), we were worried that some corporate lawyer might not approve of our use of a tool bound to such a license.
The website of JSLint is very old-school and does not contain any explanations of the ruleset or any information to get a link between the error messages provided by JSLint and the problem in the code. So you have to search through the internet to find any third-party explanation that will help you to fix the problem.
Some of the rules of JSLint are, at least, strangely named. There is a rule to forbid (or allow, if deactivated) ‘stupidity’. The project’s web page does not provide any explanation (again) - resorting to Google, we found out that ‘stupidity’ referred to the usage of synchronous functions in Node.js’s file system module.
The rule set is very strict and, when you look through the GitHub issues and pull requests, it is very hard to participate in the JSLint project. That’s why the community is very small and there are a lot more people active in JSHint and other projects and bring in their ideas there. Maybe that is why JSLint does not provide a rule similar to ‘latedef’ from JSHint or ‘no-use-before-define’ from ESLint. Without this rule it is very hard to structure your code with private named-functions at the end without assigning the function to a variable at the start (and that would not be what we want).
The Closure Linter is part of Google’s Closure tool set. It was designed for internal use and provides very little options for customization. Since following the rules enforced by it seems to be mandatory within Google, that is certainly an acceptable practice. However, since it is (for example) not possible to change the default maximum line length of 80 characters, we quickly decided not to look into the tool any more.
When looking at ESLint, we were quick to decide that we might be looking at a potential winner:
While the project is (by far) the youngest (or as others might put it: the least mature) of the four tools we looked at, it is also the best maintained. 100+ contributors on Github and a roughly monthly release schedule speak for themselves.
The output is quite handy: It prints both a one-line human readable error message as well as an error code for a quick lookup in the documentation.
The criteria from above has been weighted from five to 15, from not important to important, and the tools got a 0, 0.5 or 1 if it does not, almost or absolute fulfill the criterion.
As you can see in the image above, ESLint proved to be the winner of our evaluation. We decided that its major flaw, the potential immaturity, was acceptable to us since by its nature, it would only be used during (internal) development. The ease of use, both because of the robust and reasonable default rule set and the high-quality documentation, outweighed any concern by far. We are looking forward to adopt ESLint into our development tool chain over the coming weeks and months!