eslint-config-jessy

0.1.0 • Public • Published

Jessy, A Javascript Coding Style

travis npm downloads

Just another Javascript coding style with an eslint shareable config.

Install

  npm install --save-dev eslint-config-jessy

Then inside your .eslintrc.js file, you can write

{ extends: 'jessy' // https://github.com/lucidogen/jessy
, 'rules':         // add your custom rules here
  {
  }
}

Motivation

With the release of Javascript ES2015 (ES6), we can take the chance to change some habits regarding the code we write in Javascript, especially regarding punctuation. For this 'exercise', let's try to view Javascript as a totally new language and not let ourselves driven away by styling rules that seem weird at first sight.

Javascript is not english. We do not write phrases ending with dots or use parenthesis, commas and semicolon in the same way as in english (or french or any spoken language). We can stick to the old conventions for any good or bad reason, but with this document, we felt it could be fun to read the Javascript specs and get the most out of it in terms of:

  • Readability

Adding spaces between expressions adds visual identification of the elements and helps readability. This means adding a space before and after parenthesis, around symbols and other punctuation marks.

  • Scope readability

Some eyes are not perfect balls (astigmatism) so it is hard for some people to align things with identation. We should try to help by having some kind of consistency between opening and closing scope character positioning. Basically, it should look obvious if we missed out a comma or some punctuation or if we replaced a brace with a parenthesis or vice versa. This is particularly true for the actual trend in 'declarative Javascript' where we find ourselves often defining objects and less often writing procedural code.

  • Refactoring ease

If we need to move code around, we should not need to change too much punctuation or indentation in order to 'sit' this code in the new context.

  • Single line commit changes

It is nice if we can keep changes from spilling on lines not really concerned by the change. For example, adding an element in a list should not make it as if we changed neighboring elements in the same operation.

  • Orthogonality

This goal is to try to find a styling guide that is as consistent as possible across conditionals, object definitions, callbacks, etc.

Proposal

So here is the proposal. If you feel there is something that can be enhanced regarding the goals above, please send a pull request.

Object definition

Very short objects can be defined on a single line as so:

let foo = { title: 'hello' }

Longer objects should be defined on multiple lines, with commas at the start of each element. In this manner, all punctuation for the object definition align (opening curly bracket, commas and closing curly bracket). Note that we are not indenting the first curly bracket.

let person = 
{ firstName: 'John'
, lastName:  'Difool'
, age:       45
}

Nested object definitions should follow the same rule, with increasing indentation corresponding to nesting depth.

let effect =
{ fx: 'mix'
, mix: 0.5
, source1:
  { fx: 'video'
  , src: '/my/crazy/cat.mp4'
  , rate: 0.6
  }
, source2:
  { fx: 'quasicrystals'
  , saturation: 0.8
  }
}

Object definition with functions should follow the same rules.

let handler =
{ url: '/foo/bar/baz'
, callback ( msg ) {
    console.log ( 'Receiving', msg.url, msg.value )
  }
}

Conditional

We use 'stroustrup' brace style for functions and conditionals. Regarding parenthesis, we use spaces just as with object definitions (more on parenthesis further down).

if ( hero.isHome ) {
  hero.rest ()
  hero.giveSomeLove ()
}
else {
  hero.explore ( World )
}

Single line blocks in conditionals can be simplified by removing curly braces. But execution block never goes on the same line as the condition.

if ( hero.isHome )
  hero.rest ()
else
  hero.explore ( World )

Function definition

Function definitions look similar to conditionals. The function keyword and parameters should be on the same line as the equal sign if there is one.

const setup = function ( params ) {
  console.log ( 'Starting setup...' )
  callMum ()
  sayHelloToDad ( params.wordOfTheDay )
  makeCoffee ()
}

When using return with a new object, we need to bend the rules a little since we cannot simply describe the object on the next line. In this case, we put the opening brace with the return statement.

export function mockUser ( firstName, lastName ) {
  return {
    firstName
  , lastName
  , login: firstName
  , password: 'testing'
  }
}

When returning a complex expression, we should split it into multiple lines, aligning elements after the return keyword.

let test = function ( a, b, c, d ) {
  return a
      && b
      && ! c
      && d
}
 

Arrow function

Without a block, these are treated like any expression. With a block, we consider them like function definitions:

let foo = bar.map ( e => e.replace ( /foo/, 'bar' ) )
const setup = ( params ) => {
  console.log ( 'Starting setup...' )
  callMum ()
  sayHelloToDad ( params.wordOfTheDay )
  makeCoffee ()
}
 
let foo = baz.map
( ( e, i ) => {
    let name = ID_TO_NAME [ e ]
    return `param ${ i }${ name }`
  }
)

Try / catch

These are treated like conditionals, with the block starting on the next line.

try {
  doThis ()
  doThat ()
}
catch ( e ) {
  rescueThat ( e )
}

An empty 'catch' will have both curly braces on the next line. Having an empty catch can usually be avoided and makes the code easier to read.

Function call

Long function calls should go on multiple lines. Create a newline after the function name in case of assignment. This makes code slightly more readable and avoids too many lines with a single variable or function name:

let compiledWrapper = runInThisContext ( wrapper, { filename: filename } )
 
// or
 
let compiledWrapper = runInThisContext
( wrapper
, { filename: filename
  , more: options
  , blah: blih
  }
)

Chained calls are either contained on a single line (rare case) or split on different lines, new calls should start on the same line as the first call.

this.get ( 'model' )
.set ( 'title', title )
.set ( 'description', description )

Accessing object properties

We treat square brackets in the same manner as parenthesis or curly braces:

let c = components [ name ]

String interpolation

Use a space around interpolated elements.

throw new Error
( `Cannot watch path '${ path }' (not a relative or absolute path).` )

Real-world example

Here are some examples in order to evaluate if the desired goals are or seem to be reached by comparing some real-world examples.

Defining an animation in Ember's Liquid-fire.

// Jessy style
import { animate, stop, Promise } from 'liquid-fire'
 
export default function crossFade ( opts = {} ) {
  stop ( this.oldElement )
  return Promise.all
  ( [ animate
      ( this.oldElement
      , { opacity: 0 }
      , opts
      )
    , animate
      ( this.newElement
      , { opacity: [ opts.maxOpacity || 1, 0 ] }
      , opts
      )
    ]
  )
}

Compared to:

// Classic style
import { animate, stop, Promise } from 'liquid-fire';
 
export default function crossFade(opts = {}) {
  stop(this.oldElement);
  return Promise.all([
    animate(this.oldElement, {opacity: 0}, opts),
    animate(this.newElement, {opacity: [opts.maxOpacity || 1, 0]}, opts)
  ]);
}

Package Sidebar

Install

npm i eslint-config-jessy

Weekly Downloads

0

Version

0.1.0

License

MIT

Last publish

Collaborators

  • gbucher