ESLint

A brief history...

A man named Crockford thought there were only a few good parts to JavaScript.

He also thought we were doing it wrong...

And made JSLint to police how you write JavaScript

Problems ...

  • Too strict
  • Too opinionated
  • One mans opinions
  • Made develoeprs cry

Solutions ...

JSHint

  • The kinder linter
  • Configuerable rules

ESLint

  • Linting
  • Configurable
  • Every rule is a plugin
  • Agenda free
  • Style checking

The Philosophy of ESLint

  • Every rule is Pluggable
  • Every rule is standalone
  • Every rule can be turned off or on
  • Every rule can be a warning or an error
  • Agenda free - ESLint does not promote any particular coding style

Configuring ESLint

.eslintrc

{
  "env": {
    "browser": true,
    "node": true
  },
  "globals": {
    "angular": true
  },
  "rules": {
    "semi": 2,
    "camelcase": 2,
    "curly": 2,
    "brace-style": [2, "1tbs"],
    "quotes": [2, "single"],
    "semi": [2, "always"],
    "space-in-brackets": [2, "never"],
    "space-infix-ops": 2,
    "space-after-keywords": [2, "always"],
    "dot-notation": 2,
    "eqeqeq": [2, "smart"],
    "no-use-before-define": 2,
    "no-redeclare": 2,
    "no-inner-declarations": "both",
    "no-unused-vars": [2, {"vars": "all", "args": "after-used"}],
    "no-floating-decimal": 2,
    "no-spaced-func": 2,
    "no-extra-parens": 1,
    "no-underscore-dangle": 0,
    "valid-jsdoc": 1,
    "space-after-keywords": 2,
    "max-len": [2, 120],
    "no-use-before-define": [2, "nofunc"],
    "no-warning-comments": 0,
    "strict": 0,
    "eol-last": 0
  }
}

In file configuration

Disable everything

or just a rule

/* eslint-disable */

var obj = { key: 'value', }; // I don't care about IE8

/* eslint-enable */
/*eslint-disable no-alert */

alert('doing awful things');

/* eslint-enable no-alert */

or just tweak it

/* eslint no-comma-dangle:1 */

var obj = { key: 'value', } // Make this just a warning, not an error

your-project
├── .eslintrc
├── lib
│ └── source.js
└─┬ tests
  ├── .eslintrc
  └── test.js

Cascading and Hirearchy

Project specific settings, and directory overrides.

Using ESLint

integrations and cli

Plugins available for...

  • Sublime
  • Vim
  • Emacs
  • TextMate2
  • Atom.io
  • WebStorm

Sublime

As you type ...

On save ...

Gulp

gulp-eslint

/**
 * JavaScript Linting Task
 */
gulp.task('lint', function() {
  return gulp.src('client/app/**/*.js')
    .pipe(reload({stream: true, once: true}))
    .pipe(eslint())
    .pipe(eslint.format());
});

CLI

Possible Errors

  • no-comma-dangle
  • no-cond-assign
  • no-console
  • no-cosntant-condition
  • valid-typeof
  • no-debugger
  • no-dupe-keys
  • no-unreachable
  • ...and more

Best Practices

  • blocked-scope-var
  • complexity
  • consistent-return
  • curly
  • default-case
  • dot-notation
  • eqeqeq
  • no-alert
  • ... and more

What does it have rules for?

Variables

  • no-catch-shadow
  • no-delete-var
  • no label-var
  • no-shadow
  • no-use-before-define
  • ... and more

Node.js

  • handle-callback-err
  • no-mixed-requires
  • no-new-requires
  • no-path-concat
  • no-process-exit
  • ..and more

Stylistic issues

  • indent
  • brace-style
  • camelcase
  • func-style
  • max-nested-callbacks
  • no-space-before-semi
  • no-underscore-dangle
  • ... and more

.... and more

That isn't enough?

Write your own

module.exports = function(context) {

  'use strict';

  function report(node) {
    context.report(node,
    'You should use the $timeout service instead of the default window.setTimeout method', 
    {});
  }

  return {

    'CallExpression': function(node) {
      if (node.callee.type === 'MemberExpression' && node.callee.object.name ===
        'window' && node.callee.property.name === 'setTimeout') {
        report(node);
      }
    }
  };

};

eslint-plugin-angular - ng_timeout_service

What is the downside?

... there is always a downside

Slower

2x-3x per file

[18:52:10] Finished 'jhint' after 1.3 s
[18:53:04] Finished 'lint' after 2.24 s
  • 137 files
  • 7062 lines of code

What is the practical impact on...

JSHint

ESLint

Why is it slower?

It uses Espree to construct an AST,

THEN

evaluates your code

JSHint evaluates your code as it parses.

Should we use it?

.... I think so

  • Performance impact is worth the trade offs
  • Can lint for common errors
  • Can style check
  • Can create custom rules
  • Can specify language options
    • Enable ES6 features
    • Using react? enable JSX features

Useful Rules

no-shadow

var a = 3;
function b() {
    var a = 10;
}

no-redeclare

var a = 3;
var a = 10;

no-inner-declarations

// Good
var foo = 42;

// Bad
while (test) {
    var bar;
}
can help prevent issues with hoisting

no-unreachable

function fn() {
    x = 1;
    return x;
    x = 3; // this will never execute
}

valid-jsdoc

/**
 * Adds two numbers together.
 * @param {int} num1 The first number.
 * @param {int} num2 The second number.
 * @returns {int} The sum of the two numbers.
 */
function sum(number1, num2) {
    return number1 + num2;
}
if your going to document, document it right.

block-scoped-var

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

Code Complexity

  • complexity
  • max-depth
  • max-len
  • max-statements
  • max-nested-callbacks
  • max-params

Make our own rules

Potential rules from our guidelines

  • Use one var per variable
  • Avoid function declarations in blocks
  • Name your "anonymous" functions
  • Consider the else
  • Throw good errors
  • Use braces with blocks
  • Set to null to delete
  • Keep your hands off prototypes of built-in objects
  • Capitalize names of AngularJS controller
  • Do not use "Hungarian notation"
  • Do not use Angular's prefixes. Use your own

... some of these are already available

Potential rules from our guidelines

  • Avoid long promis chains
  • Catch errors in promises
  • Use .then(null, errorHandler)
  • Avoid $q.defer

... some of these are already available

When to lint?

early and often, but..

  • pre-commit hooks?
  • on CI?
  • before merging?

Intro to ESLint

By Evan Schultz

Intro to ESLint

  • 1,788