JavaScript Linters

Linting

Syntax validation to eliminate suspicious code and violations of code style.

Suspicious code (bugs potentially)

Undefined variables

function bad() {
    return foo;
}

Suspicious code (bugs potentially)

Lack of brackets

if (someVal)
    someVal += otherVal;
    someVal++;
    return someVal;    

Code Style

Invalid

function BAD_func (b , c){ 
      var a = 3333
    return a;
  }

Valid

function goodFunc(b, c) { 
    var a = 3333;
    return a;
}

JSLint

JSHint

How to use

.jshintrc

{
    "bitwise"       : true,
    "camelcase"     : true, 
    "quotmark"      : "single",

    "node": true,

    "globals": {
        "foo": true,
        "bar": false // readonly
    }
}

Configuration per file

/*globals foo: false, baz: false */
/*jshint camelcase: false */

var bar = 444;

/* jshint ignore:start */
foo = 777;
var FooBar = 888;
/* jshint ignore:end */

Output

var foo = function() {
    return a;
};
jshint example.js
example1.js: line 2, col 5, Missing "use strict" statement.
example1.js: line 2, col 12, 'a' is not defined.
example1.js: line 1, col 8, 'foo' is defined but never used.

3 errors

Favorite rules

undef Require all non-global variables to be declared (prevents global leaks)

Not valid

function bad() {
    return foo;
}

Valid

function good() {
    var foo;
    return foo;
}

unused Require all defined variables be used

Not valid

function bad(baz) {
    var foo = 5;
    return foo;
}

Valid

function good() {
    var foo = 5;
    return foo;
}

asi Require semicolons

Not valid

function bad(baz) {
    var foo = 5
    return foo
}

Valid

function good() {
    var foo = 5;
    return foo;
}

curly Require {} for every new block or scope

Not valid

function bad(baz) {
    if (baz > 5)
        return baz;
    return 10;
}

Valid

function good() {
    if (baz > 5) {
        return baz;
    }
    return 10;
}

newcap Require capitalization of all constructor functions

camelcase Identifiers must be in camelCase

Not valid

var my_bar = new bar();

Valid

var myBar = new Bar();

indent Spaces to indent

quotmark Quotation mark

Not valid

function bad(){
return 'foo' + "bar";
}

Valid

function bad(){
    return 'foo' + 'bar';
}

Under the trunk

JSHint 3.0

Enter Esprima

ESLint

Same configuration as JSHint

Favorite rules

no-dupe-keys Disallow duplicate keys

Not valid

var foo = {
    bar: "baz",
    bar: "qux"
};

Valid

var foo = {
    bar: "baz"
};

block-scoped-vars Threat var as block scoped

Not valid

function doSomething(a) {
    if (a) {
        var build = true;
    }
    console.log(build);
}

Valid

function doSomething(a) {
    var build;
    if (a) {
        build = true;
    }
    console.log(build);
}

consistent-this Require consistent this

"consistent-this": [2, "self"]

Not valid

var that = this;

Valid

var self = this;

func-style Enforce function style

"func-style": [2, "expression"]

Not valid

function foo(){};

Valid

var foo = function(){};

radix require radix for parseInt

Not valid

var a = parseInt("055");

Valid

var a = parseInt("055", 10);

semi can enforce absent of semi

semi: [2, "never"]

Drawbacks

JSCS

Favorite rules

disallowImplicitTypeConversion

Not valid

var a = !!someVar;
var b = +someInt;
var c = '' + someStr;

Valid

var a = Boolean(someVar);
var b = Integer(someInt);
var c = String(someStr);

requireCurlyBraces Requires curly braces after statements

{
    "requireCurlyBraces": [
        "if",
        "else",
        "for",
        "while",
        "do",
        "try",
        "catch"
    ]
}

requireSpaceAfterKeywords, disallowSpaceAfterKeywords

{
    "requireSpaceAfterKeywords": [
        "if",
        "else",
        "for",
        "while",
        "do",
        "switch",
        "return",
        "try",
        "catch",
        "case"
    ],
    "disallowSpaceAfterKeywords": [
        "default"
    ]
}

All code style

Integration (when CLI is not enough)

Editors

SublimeLinter

...and all other editors

CI

Computer, fix my code

EditorConfig

Favorite options

root = true

[*]
indent_style = space
indent_size = 4
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[*.{md,jade}]
trim_trailing_whitespace = false

JavaScript Formatters

JS Beautifier

Favorite rules

{    
    "indent_size": 4,
    "indent_char": " ",
    "indent_level": 0,

    "preserve_newlines": true,
    "max_preserve_newlines": 2,

    "jslint_happy": false,
    "brace_style": "collapse",

    "keep_array_indentation": false,
    "keep_function_indentation": false,
    "space_before_conditional": true,
    "space_in_paren": false,
}

Example

Before

var a   = 33;
var obj = { a :  33,
    b: "bzzz"
    };
if(a>3){console.log( a);}

After

var a = 33;
var obj = {
    a: 33,
    b: "bzzz"
};
if (a > 3) {
    console.log(a);
}

ESFormatter

Rules

{
    "lineBreak": {
        "before": {
            "AssignmentExpression": 1,
            "BlockStatement": 0
            // ....
        },
        "after": {
            "AssignmentExpression": 1,
            "BlockStatement": 1
            // ....
        }
    },
    "whitespace": {
        "before": {
            "ArrayExpressionOpening": 0,
            "ArrayExpressionClosing": 0,
            // ...
        },
        "after": {
            "ArrayExpressionOpening": 2,
            "ArrayExpressionClosing": 0,
            // ...
        }
    }
}

Example

Before

Q
    .when(doSomething())
    .then(function() {
        return 333;
    });

After

Q
    .when(doSomething())
    .then(function() {
    return 333;
});

Integration

Plan to follow

  1. Install EditorConfig
  2. Install your favorite linters and add them to your favorite editor
  3. Try to lint your existing code
  4. Play with settings
  5. Try to install and configure formatters

Quick way

$ npm install -g generator-linters

Thank you!