diff --git a/README.md b/README.md index 6c3762839a..a3db07c3a5 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,6 @@ -# Airbnb JavaScript Style Guide() { +# ESanity JavaScript Style Guide() { -*A mostly reasonable approach to JavaScript* - -[![Downloads](https://img.shields.io/npm/dm/eslint-config-airbnb.svg)](https://www.npmjs.com/package/eslint-config-airbnb) -[![Gitter](https://badges.gitter.im/Join Chat.svg)](https://gitter.im/airbnb/javascript?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) - -Other Style Guides - - [ES5](es5/) - - [React](react/) - - [CSS & Sass](https://github.com/airbnb/css) - - [Ruby](https://github.com/airbnb/ruby) +*A mostly reasonable approach to JavaScript, based on the Airbnb styleguide.* ## Table of Contents @@ -66,7 +57,7 @@ Other Style Guides bar = 9; - console.log(foo, bar); // => 1, 9 + console.log( foo, bar ); // => 1, 9 ``` - [1.2](#1.2) **Complex**: When you access a complex type you work on a reference to its value. @@ -80,7 +71,7 @@ Other Style Guides bar[0] = 9; - console.log(foo[0], bar[0]); // => 9, 9 + console.log( foo[0], bar[0] ); // => 9, 9 ``` **[⬆ back to top](#table-of-contents)** @@ -108,13 +99,13 @@ Other Style Guides ```javascript // bad var count = 1; - if (true) { + if ( true ) { count += 1; } // good, use the let. let count = 1; - if (true) { + if ( true ) { count += 1; } ``` @@ -127,8 +118,8 @@ Other Style Guides let a = 1; const b = 1; } - console.log(a); // ReferenceError - console.log(b); // ReferenceError + console.log( a ); // ReferenceError + console.log( b ); // ReferenceError ``` **[⬆ back to top](#table-of-contents)** @@ -187,7 +178,7 @@ Other Style Guides ```javascript - function getKey(k) { + function getKey( k ) { return `a key named ${k}`; } @@ -196,16 +187,18 @@ Other Style Guides id: 5, name: 'San Francisco', }; - obj[getKey('enabled')] = true; + obj[getKey( 'enabled' )] = true; // good const obj = { id: 5, name: 'San Francisco', - [getKey('enabled')]: true, + [getKey( 'enabled' )]: true, }; ``` + Note that computed property names do not have whitespace between the brackets and computed name as other variable property getters do. + - [3.5](#3.5) Use object method shorthand. @@ -214,7 +207,7 @@ Other Style Guides const atom = { value: 1, - addValue: function (value) { + addValue: function ( value ) { return atom.value + value; }, }; @@ -223,7 +216,7 @@ Other Style Guides const atom = { value: 1, - addValue(value) { + addValue( value ) { return atom.value + value; }, }; @@ -248,9 +241,10 @@ Other Style Guides }; ``` - - [3.7](#3.7) Group your shorthand properties at the beginning of your object declaration. + - [3.7](#3.7) Group your shorthand properties at the end of your object declaration. - > Why? It's easier to tell which properties are using the shorthand. + > Why? It's easier to tell which properties are using the shorthand, and the + > configurable properties are prioritized above the pass-through properties. ```javascript const anakinSkywalker = 'Anakin Skywalker'; @@ -258,22 +252,22 @@ Other Style Guides // bad const obj = { + anakinSkywalker, episodeOne: 1, twoJediWalkIntoACantina: 2, lukeSkywalker, episodeThree: 3, mayTheFourth: 4, - anakinSkywalker, }; // good const obj = { - lukeSkywalker, - anakinSkywalker, episodeOne: 1, twoJediWalkIntoACantina: 2, episodeThree: 3, mayTheFourth: 4, + lukeSkywalker, + anakinSkywalker, }; ``` @@ -297,10 +291,10 @@ Other Style Guides const someStack = []; // bad - someStack[someStack.length] = 'abracadabra'; + someStack[ someStack.length ] = 'abracadabra'; // good - someStack.push('abracadabra'); + someStack.push( 'abracadabra' ); ``` @@ -313,17 +307,17 @@ Other Style Guides let i; for (i = 0; i < len; i++) { - itemsCopy[i] = items[i]; + itemsCopy[ i ] = items[ i ]; } // good - const itemsCopy = [...items]; + const itemsCopy = [ ...items ]; ``` - [4.4](#4.4) To convert an array-like object to an array, use Array#from. ```javascript - const foo = document.querySelectorAll('.foo'); - const nodes = Array.from(foo); + const foo = document.querySelectorAll( '.foo' ); + const nodes = Array.from( foo ); ``` **[⬆ back to top](#table-of-contents)** @@ -336,7 +330,7 @@ Other Style Guides ```javascript // bad - function getFullName(user) { + function getFullName( user ) { const firstName = user.firstName; const lastName = user.lastName; @@ -344,28 +338,47 @@ Other Style Guides } // good - function getFullName(obj) { + function getFullName( obj ) { const { firstName, lastName } = obj; return `${firstName} ${lastName}`; } // best - function getFullName({ firstName, lastName }) { + function getFullName( { firstName, lastName } ) { return `${firstName} ${lastName}`; } ``` + When destructuring a large object, do it at the top of the closure on its + own, broken into separate lines when more than two objects are being + destructured: + + ```javascript + // bad + function getFullName() { + const { foo: { bar, baz }, bar: { bang } } = this; + } + + // good + function getFullName() { + const { + bar: { bang }, + foo: { bar, baz } , + } = this; + } + ``` + - [5.2](#5.2) Use array destructuring. ```javascript - const arr = [1, 2, 3, 4]; + const arr = [ 1, 2, 3, 4 ]; // bad const first = arr[0]; const second = arr[1]; // good - const [first, second] = arr; + const [ first, second ] = arr; ``` - [5.3](#5.3) Use object destructuring for multiple return values, not array destructuring. @@ -374,22 +387,22 @@ Other Style Guides ```javascript // bad - function processInput(input) { + function processInput( input ) { // then a miracle occurs - return [left, right, top, bottom]; + return [ left, right, top, bottom ]; } // the caller needs to think about the order of return data - const [left, __, top] = processInput(input); + const [ left, __, top ] = processInput( input ); // good - function processInput(input) { + function processInput( input ) { // then a miracle occurs return { left, right, top, bottom }; } // the caller selects only the data they need - const { left, right } = processInput(input); + const { left, right } = processInput( input ); ``` @@ -433,17 +446,17 @@ Other Style Guides ```javascript // bad - function sayHi(name) { + function sayHi( name ) { return 'How are you, ' + name + '?'; } // bad - function sayHi(name) { - return ['How are you, ', name, '?'].join(); + function sayHi( name ) { + return [ 'How are you, ', name, '?' ].join(); } // good - function sayHi(name) { + function sayHi( name ) { return `How are you, ${name}?`; } ``` @@ -473,7 +486,7 @@ Other Style Guides ```javascript // immediately-invoked function expression (IIFE) (() => { - console.log('Welcome to the Internet. Please follow me.'); + console.log( 'Welcome to the Internet. Please follow me.' ); })(); ``` @@ -482,17 +495,17 @@ Other Style Guides ```javascript // bad - if (currentUser) { + if ( currentUser ) { function test() { - console.log('Nope.'); + console.log( 'Nope.' ); } } // good let test; - if (currentUser) { + if ( currentUser ) { test = () => { - console.log('Yup.'); + console.log( 'Yup.' ); }; } ``` @@ -501,12 +514,12 @@ Other Style Guides ```javascript // bad - function nope(name, options, arguments) { + function nope( name, options, arguments ) { // ...stuff... } // good - function yup(name, options, args) { + function yup( name, options, args ) { // ...stuff... } ``` @@ -519,13 +532,13 @@ Other Style Guides ```javascript // bad function concatenateAll() { - const args = Array.prototype.slice.call(arguments); - return args.join(''); + const args = Array.prototype.slice.call( arguments ); + return args.join( '' ); } // good - function concatenateAll(...args) { - return args.join(''); + function concatenateAll( ...args ) { + return args.join( '' ); } ``` @@ -534,7 +547,7 @@ Other Style Guides ```javascript // really bad - function handleThings(opts) { + function handleThings( opts ) { // No! We shouldn't mutate function arguments. // Double bad: if opts is falsy it'll be set to an object which may // be what you want but it can introduce subtle bugs. @@ -543,15 +556,15 @@ Other Style Guides } // still bad - function handleThings(opts) { - if (opts === void 0) { + function handleThings( opts ) { + if ( opts === void 0 ) { opts = {}; } // ... } // good - function handleThings(opts = {}) { + function handleThings( opts = {} ) { // ... } ``` @@ -563,8 +576,8 @@ Other Style Guides ```javascript var b = 1; // bad - function count(a = b++) { - console.log(a); + function count( a = b++ ) { + console.log( a ); } count(); // 1 count(); // 2 @@ -576,12 +589,12 @@ Other Style Guides ```javascript // bad - function handleThings(opts = {}, name) { + function handleThings( opts = {}, name ) { // ... } // good - function handleThings(name, opts = {}) { + function handleThings( name, opts = {} ) { // ... } ``` @@ -592,10 +605,10 @@ Other Style Guides ```javascript // bad - var add = new Function('a', 'b', 'return a + b'); + var add = new Function( 'a', 'b', 'return a + b' ); // still bad - var subtract = Function('a', 'b', 'return a - b'); + var subtract = Function( 'a', 'b', 'return a - b' ); ``` **[⬆ back to top](#table-of-contents)** @@ -610,13 +623,13 @@ Other Style Guides ```javascript // bad - [1, 2, 3].map(function (x) { + [ 1, 2, 3 ].map(function( x ) { const y = x + 1; return x * y; }); // good - [1, 2, 3].map((x) => { + [ 1, 2, 3 ].map( x => { const y = x + 1; return x * y; }); @@ -630,16 +643,16 @@ Other Style Guides ```javascript // good - [1, 2, 3].map(number => `A string containing the ${number}.`); + [ 1, 2, 3 ].map( number => `A string containing the ${number}.` ); // bad - [1, 2, 3].map(number => { + [1, 2, 3].map( number => { const nextNumber = number + 1; `A string containing the ${nextNumber}.`; }); // good - [1, 2, 3].map(number => { + [ 1, 2, 3 ].map( number => { const nextNumber = number + 1; return `A string containing the ${nextNumber}.`; }); @@ -651,13 +664,13 @@ Other Style Guides ```js // bad - [1, 2, 3].map(number => 'As time went by, the string containing the ' + + [ 1, 2, 3 ].map( number => 'As time went by, the string containing the ' + `${number} became much longer. So we needed to break it over multiple ` + 'lines.' ); // good - [1, 2, 3].map(number => ( + [ 1, 2, 3 ].map( number => ( `As time went by, the string containing the ${number} became much ` + 'longer. So we needed to break it over multiple lines.' )); @@ -670,10 +683,10 @@ Other Style Guides ```js // good - [1, 2, 3].map(x => x * x); + [ 1, 2, 3 ].map( x => x * x ); // good - [1, 2, 3].reduce((y, x) => x + y); + [ 1, 2, 3 ].reduce( ( y, x ) => x + y ); ``` **[⬆ back to top](#table-of-contents)** @@ -687,24 +700,24 @@ Other Style Guides ```javascript // bad - function Queue(contents = []) { - this._queue = [...contents]; + function Queue( contents = [] ) { + this._queue = [ ...contents ]; } Queue.prototype.pop = function() { const value = this._queue[0]; - this._queue.splice(0, 1); + this._queue.splice( 0, 1 ); return value; } // good class Queue { - constructor(contents = []) { - this._queue = [...contents]; + constructor( contents = [] ) { + this._queue = [ ...contents ]; } pop() { const value = this._queue[0]; - this._queue.splice(0, 1); + this._queue.splice( 0, 1 ); return value; } } @@ -716,11 +729,11 @@ Other Style Guides ```javascript // bad - const inherits = require('inherits'); - function PeekableQueue(contents) { - Queue.apply(this, contents); + const inherits = require( 'inherits' ); + function PeekableQueue( contents ) { + Queue.apply( this, contents ); } - inherits(PeekableQueue, Queue); + inherits( PeekableQueue, Queue ); PeekableQueue.prototype.peek = function() { return this._queue[0]; } @@ -742,13 +755,13 @@ Other Style Guides return true; }; - Jedi.prototype.setHeight = function(height) { + Jedi.prototype.setHeight = function( height ) { this.height = height; }; const luke = new Jedi(); luke.jump(); // => true - luke.setHeight(20); // => undefined + luke.setHeight( 20 ); // => undefined // good class Jedi { @@ -757,7 +770,7 @@ Other Style Guides return this; } - setHeight(height) { + setHeight( height ) { this.height = height; return this; } @@ -766,7 +779,7 @@ Other Style Guides const luke = new Jedi(); luke.jump() - .setHeight(20); + .setHeight( 20 ); ``` @@ -774,7 +787,7 @@ Other Style Guides ```javascript class Jedi { - constructor(options = {}) { + constructor( options = {} ) { this.name = options.name || 'no name'; } @@ -799,7 +812,7 @@ Other Style Guides ```javascript // bad - const AirbnbStyleGuide = require('./AirbnbStyleGuide'); + const AirbnbStyleGuide = require( './AirbnbStyleGuide' ); module.exports = AirbnbStyleGuide.es6; // ok @@ -847,11 +860,11 @@ Other Style Guides > Why? This enforces our immutable rule. Dealing with pure functions that return values is easier to reason about than side-effects. ```javascript - const numbers = [1, 2, 3, 4, 5]; + const numbers = [ 1, 2, 3, 4, 5 ]; // bad let sum = 0; - for (let num of numbers) { + for ( let num of numbers ) { sum += num; } @@ -859,11 +872,11 @@ Other Style Guides // good let sum = 0; - numbers.forEach((num) => sum += num); + numbers.forEach( num => sum += num ); sum === 15; // best (use the functional force) - const sum = numbers.reduce((total, num) => total + num, 0); + const sum = numbers.reduce( ( total, num ) => total + num, 0 ); sum === 15; ``` @@ -885,7 +898,7 @@ Other Style Guides }; // bad - const isJedi = luke['jedi']; + const isJedi = luke[ 'jedi' ]; // good const isJedi = luke.jedi; @@ -899,11 +912,11 @@ Other Style Guides age: 28, }; - function getProp(prop) { - return luke[prop]; + function getProp( prop ) { + return luke[ prop ]; } - const isJedi = getProp('jedi'); + const isJedi = getProp( 'jedi' ); ``` **[⬆ back to top](#table-of-contents)** @@ -976,7 +989,7 @@ Other Style Guides // good function() { test(); - console.log('doing stuff..'); + console.log( 'doing stuff..' ); //..other stuff.. @@ -990,26 +1003,26 @@ Other Style Guides } // bad - unnecessary function call - function(hasName) { + function( hasName ) { const name = getName(); - if (!hasName) { + if ( !hasName ) { return false; } - this.setFirstName(name); + this.setFirstName( name ); return true; } // good - function(hasName) { - if (!hasName) { + function( hasName ) { + if ( !hasName ) { return false; } const name = getName(); - this.setFirstName(name); + this.setFirstName( name ); return true; } @@ -1026,7 +1039,7 @@ Other Style Guides // we know this wouldn't work (assuming there // is no notDefined global variable) function example() { - console.log(notDefined); // => throws a ReferenceError + console.log( notDefined ); // => throws a ReferenceError } // creating a variable declaration after you @@ -1034,7 +1047,7 @@ Other Style Guides // variable hoisting. Note: the assignment // value of `true` is not hoisted. function example() { - console.log(declaredButNotAssigned); // => undefined + console.log( declaredButNotAssigned ); // => undefined var declaredButNotAssigned = true; } @@ -1043,14 +1056,14 @@ Other Style Guides // which means our example could be rewritten as: function example() { let declaredButNotAssigned; - console.log(declaredButNotAssigned); // => undefined + console.log( declaredButNotAssigned ); // => undefined declaredButNotAssigned = true; } // using const and let function example() { - console.log(declaredButNotAssigned); // => throws a ReferenceError - console.log(typeof declaredButNotAssigned); // => throws a ReferenceError + console.log( declaredButNotAssigned ); // => throws a ReferenceError + console.log( typeof declaredButNotAssigned ); // => throws a ReferenceError const declaredButNotAssigned = true; } ``` @@ -1059,12 +1072,12 @@ Other Style Guides ```javascript function example() { - console.log(anonymous); // => undefined + console.log( anonymous ); // => undefined anonymous(); // => TypeError anonymous is not a function var anonymous = function() { - console.log('anonymous function expression'); + console.log( 'anonymous function expression' ); }; } ``` @@ -1073,26 +1086,26 @@ Other Style Guides ```javascript function example() { - console.log(named); // => undefined + console.log( named ); // => undefined named(); // => TypeError named is not a function superPower(); // => ReferenceError superPower is not defined var named = function superPower() { - console.log('Flying'); + console.log( 'Flying' ); }; } // the same is true when the function name // is the same as the variable name. function example() { - console.log(named); // => undefined + console.log( named ); // => undefined named(); // => TypeError named is not a function var named = function named() { - console.log('named'); + console.log( 'named' ); } } ``` @@ -1104,7 +1117,7 @@ Other Style Guides superPower(); // => Flying function superPower() { - console.log('Flying'); + console.log( 'Flying' ); } } ``` @@ -1127,7 +1140,7 @@ Other Style Guides + **Strings** evaluate to **false** if an empty string `''`, otherwise **true** ```javascript - if ([0]) { + if ( [ 0 ] ) { // true // An array is an object, objects evaluate to true } @@ -1137,22 +1150,22 @@ Other Style Guides ```javascript // bad - if (name !== '') { + if ( name !== '' ) { // ...stuff... } // good - if (name) { + if ( name ) { // ...stuff... } // bad - if (collection.length > 0) { + if ( collection.length > 0 ) { // ...stuff... } // good - if (collection.length) { + if ( collection.length ) { // ...stuff... } ``` @@ -1168,14 +1181,14 @@ Other Style Guides ```javascript // bad - if (test) + if ( test ) return false; // good - if (test) return false; + if ( test ) return false; // good - if (test) { + if ( test ) { return false; } @@ -1193,7 +1206,7 @@ Other Style Guides ```javascript // bad - if (test) { + if ( test ) { thing1(); thing2(); } @@ -1202,7 +1215,7 @@ Other Style Guides } // good - if (test) { + if ( test ) { thing1(); thing2(); } else { @@ -1225,7 +1238,7 @@ Other Style Guides // // @param {String} tag // @return {Element} element - function make(tag) { + function make( tag ) { // ...stuff... @@ -1240,7 +1253,7 @@ Other Style Guides * @param {String} tag * @return {Element} element */ - function make(tag) { + function make( tag ) { // ...stuff... @@ -1260,7 +1273,7 @@ Other Style Guides // bad function getType() { - console.log('fetching type...'); + console.log( 'fetching type...' ); // set the default type to 'no type' const type = this._type || 'no type'; @@ -1269,7 +1282,7 @@ Other Style Guides // good function getType() { - console.log('fetching type...'); + console.log( 'fetching type...' ); // set the default type to 'no type' const type = this._type || 'no type'; @@ -1356,7 +1369,7 @@ Other Style Guides }); ``` - - [18.3](#18.3) Place 1 space before the opening parenthesis in control statements (`if`, `while` etc.). Place no space before the argument list in function calls and declarations. + - [18.3](#18.3) Place 1 space before the opening parenthesis in control statements (`if`, `while` etc.) and around the arguments. ```javascript // bad @@ -1365,7 +1378,7 @@ Other Style Guides } // good - if (isJedi) { + if ( isJedi ) { fight(); } @@ -1376,9 +1389,31 @@ Other Style Guides // good function fight() { - console.log('Swooosh!'); + console.log( 'Swooosh!' ); } ``` + + - [18.3](#18.3a) Put spaces around all arguments and property getters except integer array indices. + + ```javascript + // bad + const foo = ['foo', 'bar']; + + // bad + const foo['bar'] = 'baz'; + + // bad + const foo = bar[ 0 ]; + + // good + const foo = [ 'foo', 'bar' ]; + + // good + const foo[ 'bar' ] = 'baz'; + + // good + const foo = bar[0]; + ``` - [18.4](#18.4) Set off operators with spaces. @@ -1394,24 +1429,24 @@ Other Style Guides ```javascript // bad - (function(global) { + (function( global ) { // ...stuff... - })(this); + })( this ); ``` ```javascript // bad - (function(global) { + (function( global ) { // ...stuff... - })(this);↵ + })( this );↵ ↵ ``` ```javascript // good - (function(global) { + (function( global ) { // ...stuff... - })(this);↵ + })( this );↵ ``` - [18.6](#18.6) Use indentation when making long method chains. Use a leading dot, which @@ -1419,99 +1454,41 @@ Other Style Guides ```javascript // bad - $('#items').find('.selected').highlight().end().find('.open').updateCount(); + $( '#items' ).find( '.selected' ).highlight().end().find( '.open' ).updateCount(); // bad - $('#items'). - find('.selected'). + $( '#items' ). + find( '.selected' ). highlight(). end(). - find('.open'). + find( '.open' ). updateCount(); // good - $('#items') - .find('.selected') + $( '#items' ) + .find( '.selected' ) .highlight() .end() - .find('.open') + .find( '.open' ) .updateCount(); // bad - const leds = stage.selectAll('.led').data(data).enter().append('svg:svg').class('led', true) - .attr('width', (radius + margin) * 2).append('svg:g') - .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')') - .call(tron.led); - - // good - const leds = stage.selectAll('.led') - .data(data) - .enter().append('svg:svg') - .classed('led', true) - .attr('width', (radius + margin) * 2) - .append('svg:g') - .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')') - .call(tron.led); - ``` - - - [18.7](#18.7) Leave a blank line after blocks and before the next statement. - - ```javascript - // bad - if (foo) { - return bar; - } - return baz; - - // good - if (foo) { - return bar; - } - - return baz; - - // bad - const obj = { - foo() { - }, - bar() { - }, - }; - return obj; - - // good - const obj = { - foo() { - }, - - bar() { - }, - }; - - return obj; - - // bad - const arr = [ - function foo() { - }, - function bar() { - }, - ]; - return arr; + const leds = stage.selectAll( '.led' ).data( data ).enter().append( 'svg:svg' ).class( 'led', true ) + .attr( 'width', ( radius + margin ) * 2 ).append( 'svg:g' ) + .attr( 'transform', 'translate(' + ( radius + margin ) + ',' + ( radius + margin ) + ')' ) + .call( tron.led ); // good - const arr = [ - function foo() { - }, - - function bar() { - }, - ]; - - return arr; + const leds = stage.selectAll( '.led' ) + .data( data ) + .enter().append( 'svg:svg' ) + .classed( 'led', true ) + .attr( 'width', (radius + margin) * 2 ) + .append( 'svg:g' ) + .attr( 'transform', 'translate(' + ( radius + margin ) + ',' + ( radius + margin ) + ')') + .call( tron.led ); ``` - **[⬆ back to top](#table-of-contents)** ## Commas @@ -1637,7 +1614,7 @@ Other Style Guides const totalScore = this.reviewScore + ''; // good - const totalScore = String(this.reviewScore); + const totalScore = String( this.reviewScore ); ``` - [21.3](#21.3) Use `parseInt` for Numbers and always with a radix for type casting. @@ -1646,7 +1623,7 @@ Other Style Guides const inputValue = '4'; // bad - const val = new Number(inputValue); + const val = new Number( inputValue ); // bad const val = +inputValue; @@ -1655,13 +1632,13 @@ Other Style Guides const val = inputValue >> 0; // bad - const val = parseInt(inputValue); + const val = parseInt( inputValue ); // good - const val = Number(inputValue); + const val = Number( inputValue ); // good - const val = parseInt(inputValue, 10); + const val = parseInt( inputValue, 10 ); ``` - [21.4](#21.4) If for whatever reason you are doing something wild and `parseInt` is your bottleneck and need to use Bitshift for [performance reasons](http://jsperf.com/coercion-vs-casting/3), leave a comment explaining why and what you're doing. @@ -1690,10 +1667,10 @@ Other Style Guides const age = 0; // bad - const hasAge = new Boolean(age); + const hasAge = new Boolean( age ); // good - const hasAge = Boolean(age); + const hasAge = Boolean( age ); // good const hasAge = !!age; @@ -1735,7 +1712,7 @@ Other Style Guides ```javascript // bad - function user(options) { + function user( options ) { this.name = options.name; } @@ -1745,7 +1722,7 @@ Other Style Guides // good class User { - constructor(options) { + constructor( options ) { this.name = options.name; } } @@ -1773,7 +1750,7 @@ Other Style Guides function foo() { const self = this; return function() { - console.log(self); + console.log( self ); }; } @@ -1781,19 +1758,19 @@ Other Style Guides function foo() { const that = this; return function() { - console.log(that); + console.log( that ); }; } // good function foo() { return () => { - console.log(this); + console.log( this ); }; } ``` - - [22.6](#22.6) If your file exports a single class, your filename should be exactly the name of the class. + - [22.6](#22.6) If your file exports a single class, your filename should be the snake_case version of the class name. ```javascript // file contents class CheckBox { @@ -1806,10 +1783,11 @@ Other Style Guides import CheckBox from './checkBox'; // bad - import CheckBox from './check_box'; + import CheckBox from './CheckBox'; // good - import CheckBox from './CheckBox'; + import CheckBox from './check_box'; + ``` - [22.7](#22.7) Use camelCase when you export-default a function. Your filename should be identical to your function's name. @@ -1849,10 +1827,10 @@ Other Style Guides dragon.getAge(); // bad - dragon.age(25); + dragon.age( 25 ); // good - dragon.setAge(25); + dragon.setAge( 25 ); ``` - [23.3](#23.3) If the property is a `boolean`, use `isVal()` or `hasVal()`. @@ -1873,16 +1851,16 @@ Other Style Guides ```javascript class Jedi { - constructor(options = {}) { + constructor( options = {} ) { const lightsaber = options.lightsaber || 'blue'; - this.set('lightsaber', lightsaber); + this.set( 'lightsaber', lightsaber ); } - set(key, val) { + set( key, val) { this[key] = val; } - get(key) { + get( key ) { return this[key]; } } @@ -1897,11 +1875,11 @@ Other Style Guides ```javascript // bad - $(this).trigger('listingUpdated', listing.id); + $( this ).trigger( 'listingUpdated', listing.id ); ... - $(this).on('listingUpdated', function(e, listingId) { + $( this ).on( 'listingUpdated', function( e, listingId ) { // do something with listingId }); ``` @@ -1910,11 +1888,11 @@ Other Style Guides ```javascript // good - $(this).trigger('listingUpdated', { listingId: listing.id }); + $( this ).trigger( 'listingUpdated', { listingId: listing.id } ); ... - $(this).on('listingUpdated', function(e, data) { + $( this ).on( 'listingUpdated', function( e, data ) { // do something with data.listingId }); ``` @@ -1928,13 +1906,13 @@ Other Style Guides ```javascript // bad - const sidebar = $('.sidebar'); + const sidebar = $( '.sidebar' ); // good - const $sidebar = $('.sidebar'); + const $sidebar = $( '.sidebar' ); // good - const $sidebarBtn = $('.sidebar-btn'); + const $sidebarBtn = $( '.sidebar-btn' ); ``` - [25.2](#25.2) Cache jQuery lookups. @@ -1942,18 +1920,18 @@ Other Style Guides ```javascript // bad function setSidebar() { - $('.sidebar').hide(); + $( '.sidebar' ).hide(); // ...stuff... - $('.sidebar').css({ + $( '.sidebar' ).css({ 'background-color': 'pink' }); } // good function setSidebar() { - const $sidebar = $('.sidebar'); + const $sidebar = $( '.sidebar' ); $sidebar.hide(); // ...stuff... @@ -1969,19 +1947,19 @@ Other Style Guides ```javascript // bad - $('ul', '.sidebar').hide(); + $( 'ul', '.sidebar' ).hide(); // bad - $('.sidebar').find('ul').hide(); + $( '.sidebar' ).find( 'ul' ).hide(); // good - $('.sidebar ul').hide(); + $( '.sidebar ul' ).hide(); // good - $('.sidebar > ul').hide(); + $( '.sidebar > ul' ).hide(); // good - $sidebar.find('ul').hide(); + $sidebar.find( 'ul' ).hide(); ``` **[⬆ back to top](#table-of-contents)** diff --git a/linters/.eslintrc b/linters/.eslintrc deleted file mode 100644 index 9e203a5473..0000000000 --- a/linters/.eslintrc +++ /dev/null @@ -1,5 +0,0 @@ -// Use this file as a starting point for your project's .eslintrc. -// Copy this file, and add rule overrides as needed. -{ - "extends": "airbnb" -} diff --git a/linters/README.md b/linters/README.md deleted file mode 100644 index 1deac701c7..0000000000 --- a/linters/README.md +++ /dev/null @@ -1,11 +0,0 @@ -## `.eslintrc` - -Our `.eslintrc` requires the following NPM packages: - -``` -npm install --save-dev \ - eslint-config-airbnb \ - eslint \ - babel-eslint \ - eslint-plugin-react -``` diff --git a/linters/SublimeLinter/SublimeLinter.sublime-settings b/linters/SublimeLinter/SublimeLinter.sublime-settings deleted file mode 100644 index 12360f3f1c..0000000000 --- a/linters/SublimeLinter/SublimeLinter.sublime-settings +++ /dev/null @@ -1,73 +0,0 @@ -/** - * Airbnb JSHint settings for use with SublimeLinter and Sublime Text 2. - * - * 1. Install SublimeLinter at https://github.com/SublimeLinter/SublimeLinter - * 2. Open user preferences for the SublimeLinter package in Sublime Text 2 - * * For Mac OS X go to _Sublime Text 2_ > _Preferences_ > _Package Settings_ > _SublimeLinter_ > _Settings - User_ - * 3. Paste the contents of this file into your settings file - * 4. Save the settings file - * - * @version 0.3.0 - * @see https://github.com/SublimeLinter/SublimeLinter - * @see http://www.jshint.com/docs/ - */ -{ - "jshint_options": - { - /* - * ENVIRONMENTS - * ================= - */ - - // Define globals exposed by modern browsers. - "browser": true, - - // Define globals exposed by jQuery. - "jquery": true, - - // Define globals exposed by Node.js. - "node": true, - - /* - * ENFORCING OPTIONS - * ================= - */ - - // Force all variable names to use either camelCase style or UPPER_CASE - // with underscores. - "camelcase": true, - - // Prohibit use of == and != in favor of === and !==. - "eqeqeq": true, - - // Suppress warnings about == null comparisons. - "eqnull": true, - - // Enforce tab width of 2 spaces. - "indent": 2, - - // Prohibit use of a variable before it is defined. - "latedef": true, - - // Require capitalized names for constructor functions. - "newcap": true, - - // Enforce use of single quotation marks for strings. - "quotmark": "single", - - // Prohibit trailing whitespace. - "trailing": true, - - // Prohibit use of explicitly undeclared variables. - "undef": true, - - // Warn when variables are defined but never used. - "unused": true, - - // Enforce line length to 80 characters - "maxlen": 80, - - // Enforce placing 'use strict' at the top function scope - "strict": true - } -} diff --git a/linters/jshintrc b/linters/jshintrc deleted file mode 100644 index 141067fd23..0000000000 --- a/linters/jshintrc +++ /dev/null @@ -1,62 +0,0 @@ -{ - /* - * ENVIRONMENTS - * ================= - */ - - // Define globals exposed by modern browsers. - "browser": true, - - // Define globals exposed by jQuery. - "jquery": true, - - // Define globals exposed by Node.js. - "node": true, - - // Allow ES6. - "esnext": true, - - /* - * ENFORCING OPTIONS - * ================= - */ - - // Force all variable names to use either camelCase style or UPPER_CASE - // with underscores. - "camelcase": true, - - // Prohibit use of == and != in favor of === and !==. - "eqeqeq": true, - - // Enforce tab width of 2 spaces. - "indent": 2, - - // Prohibit use of a variable before it is defined. - "latedef": true, - - // Enforce line length to 80 characters - "maxlen": 80, - - // Require capitalized names for constructor functions. - "newcap": true, - - // Enforce use of single quotation marks for strings. - "quotmark": "single", - - // Enforce placing 'use strict' at the top function scope - "strict": true, - - // Prohibit use of explicitly undeclared variables. - "undef": true, - - // Warn when variables are defined but never used. - "unused": true, - - /* - * RELAXING OPTIONS - * ================= - */ - - // Suppress warnings about == null comparisons. - "eqnull": true -} diff --git a/packages/eslint-config-airbnb/.eslintrc b/packages/eslint-config-airbnb/.eslintrc deleted file mode 100644 index cbf450f01f..0000000000 --- a/packages/eslint-config-airbnb/.eslintrc +++ /dev/null @@ -1,11 +0,0 @@ -{ - "extends": "airbnb", - "rules": { - // disable requiring trailing commas because it might be nice to revert to - // being JSON at some point, and I don't want to make big changes now. - "comma-dangle": 0, - // disabled because I find it tedious to write tests while following this - // rule - "no-shadow": 0 - } -} diff --git a/packages/eslint-config-airbnb/README.md b/packages/eslint-config-airbnb/README.md deleted file mode 100644 index ac184f1adb..0000000000 --- a/packages/eslint-config-airbnb/README.md +++ /dev/null @@ -1,35 +0,0 @@ -# eslint-config-airbnb - -This package provides Airbnb's .eslintrc as an extensible shared config. - -## Usage - -### With React Style - -1. `npm install --save-dev eslint-config-airbnb babel-eslint eslint-plugin-react` -2. add `"extends": "airbnb"` to your .eslintrc - -### Without React Style - -1. `npm install --save-dev eslint-config-airbnb babel-eslint ` -2. add `"extends": "airbnb/base"` to your .eslintrc - -See [Airbnb's Javascript styleguide](https://github.com/airbnb/javascript) and -the [ESlint config docs](http://eslint.org/docs/user-guide/configuring#extending-configuration-files) -for more information. - -## Improving this config - -Consider adding test cases if you're making complicated rules changes, like -anything involving regexes. Perhaps in a distant future, we could use literate -programming to structure our README as test cases for our .eslintrc? - -You can run tests with `npm test`. - -You can make sure this module lints with itself using `npm run lint`. - -## Changelog - -### 0.0.8 - - now has a changelog - - now is modular (see instructions above for with react and without react versions) diff --git a/packages/eslint-config-airbnb/base/index.js b/packages/eslint-config-airbnb/base/index.js deleted file mode 100644 index dad7ce9e01..0000000000 --- a/packages/eslint-config-airbnb/base/index.js +++ /dev/null @@ -1,178 +0,0 @@ -module.exports = { - 'parser': 'babel-eslint', // https://github.com/babel/babel-eslint - 'env': { // http://eslint.org/docs/user-guide/configuring.html#specifying-environments - 'browser': true, // browser global variables - 'node': true // Node.js global variables and Node.js-specific rules - }, - 'ecmaFeatures': { - 'arrowFunctions': true, - 'blockBindings': true, - 'classes': true, - 'defaultParams': true, - 'destructuring': true, - 'forOf': true, - 'generators': false, - 'modules': true, - 'objectLiteralComputedProperties': true, - 'objectLiteralDuplicateProperties': false, - 'objectLiteralShorthandMethods': true, - 'objectLiteralShorthandProperties': true, - 'spread': true, - 'superInFunctions': true, - 'templateStrings': true, - 'jsx': true - }, - 'rules': { - /** - * Strict mode - */ - // babel inserts 'use strict'; for us - 'strict': [2, 'never'], // http://eslint.org/docs/rules/strict - - /** - * ES6 - */ - 'no-var': 2, // http://eslint.org/docs/rules/no-var - 'prefer-const': 2, // http://eslint.org/docs/rules/prefer-const - - /** - * Variables - */ - 'no-shadow': 2, // http://eslint.org/docs/rules/no-shadow - 'no-shadow-restricted-names': 2, // http://eslint.org/docs/rules/no-shadow-restricted-names - 'no-undef': 2, // http://eslint.org/docs/rules/no-undef - 'no-unused-vars': [2, { // http://eslint.org/docs/rules/no-unused-vars - 'vars': 'local', - 'args': 'after-used' - }], - 'no-use-before-define': 2, // http://eslint.org/docs/rules/no-use-before-define - - /** - * Possible errors - */ - 'comma-dangle': [2, 'always-multiline'], // http://eslint.org/docs/rules/comma-dangle - 'no-cond-assign': [2, 'always'], // http://eslint.org/docs/rules/no-cond-assign - 'no-console': 1, // http://eslint.org/docs/rules/no-console - 'no-debugger': 1, // http://eslint.org/docs/rules/no-debugger - 'no-alert': 1, // http://eslint.org/docs/rules/no-alert - 'no-constant-condition': 1, // http://eslint.org/docs/rules/no-constant-condition - 'no-dupe-keys': 2, // http://eslint.org/docs/rules/no-dupe-keys - 'no-duplicate-case': 2, // http://eslint.org/docs/rules/no-duplicate-case - 'no-empty': 2, // http://eslint.org/docs/rules/no-empty - 'no-ex-assign': 2, // http://eslint.org/docs/rules/no-ex-assign - 'no-extra-boolean-cast': 0, // http://eslint.org/docs/rules/no-extra-boolean-cast - 'no-extra-semi': 2, // http://eslint.org/docs/rules/no-extra-semi - 'no-func-assign': 2, // http://eslint.org/docs/rules/no-func-assign - 'no-inner-declarations': 2, // http://eslint.org/docs/rules/no-inner-declarations - 'no-invalid-regexp': 2, // http://eslint.org/docs/rules/no-invalid-regexp - 'no-irregular-whitespace': 2, // http://eslint.org/docs/rules/no-irregular-whitespace - 'no-obj-calls': 2, // http://eslint.org/docs/rules/no-obj-calls - 'no-sparse-arrays': 2, // http://eslint.org/docs/rules/no-sparse-arrays - 'no-unreachable': 2, // http://eslint.org/docs/rules/no-unreachable - 'use-isnan': 2, // http://eslint.org/docs/rules/use-isnan - 'block-scoped-var': 2, // http://eslint.org/docs/rules/block-scoped-var - - /** - * Best practices - */ - 'consistent-return': 2, // http://eslint.org/docs/rules/consistent-return - 'curly': [2, 'multi-line'], // http://eslint.org/docs/rules/curly - 'default-case': 2, // http://eslint.org/docs/rules/default-case - 'dot-notation': [2, { // http://eslint.org/docs/rules/dot-notation - 'allowKeywords': true - }], - 'eqeqeq': 2, // http://eslint.org/docs/rules/eqeqeq - 'guard-for-in': 2, // http://eslint.org/docs/rules/guard-for-in - 'no-caller': 2, // http://eslint.org/docs/rules/no-caller - 'no-else-return': 2, // http://eslint.org/docs/rules/no-else-return - 'no-eq-null': 2, // http://eslint.org/docs/rules/no-eq-null - 'no-eval': 2, // http://eslint.org/docs/rules/no-eval - 'no-extend-native': 2, // http://eslint.org/docs/rules/no-extend-native - 'no-extra-bind': 2, // http://eslint.org/docs/rules/no-extra-bind - 'no-fallthrough': 2, // http://eslint.org/docs/rules/no-fallthrough - 'no-floating-decimal': 2, // http://eslint.org/docs/rules/no-floating-decimal - 'no-implied-eval': 2, // http://eslint.org/docs/rules/no-implied-eval - 'no-lone-blocks': 2, // http://eslint.org/docs/rules/no-lone-blocks - 'no-loop-func': 2, // http://eslint.org/docs/rules/no-loop-func - 'no-multi-str': 2, // http://eslint.org/docs/rules/no-multi-str - 'no-native-reassign': 2, // http://eslint.org/docs/rules/no-native-reassign - 'no-new': 2, // http://eslint.org/docs/rules/no-new - 'no-new-func': 2, // http://eslint.org/docs/rules/no-new-func - 'no-new-wrappers': 2, // http://eslint.org/docs/rules/no-new-wrappers - 'no-octal': 2, // http://eslint.org/docs/rules/no-octal - 'no-octal-escape': 2, // http://eslint.org/docs/rules/no-octal-escape - 'no-param-reassign': 2, // http://eslint.org/docs/rules/no-param-reassign - 'no-proto': 2, // http://eslint.org/docs/rules/no-proto - 'no-redeclare': 2, // http://eslint.org/docs/rules/no-redeclare - 'no-return-assign': 2, // http://eslint.org/docs/rules/no-return-assign - 'no-script-url': 2, // http://eslint.org/docs/rules/no-script-url - 'no-self-compare': 2, // http://eslint.org/docs/rules/no-self-compare - 'no-sequences': 2, // http://eslint.org/docs/rules/no-sequences - 'no-throw-literal': 2, // http://eslint.org/docs/rules/no-throw-literal - 'no-with': 2, // http://eslint.org/docs/rules/no-with - 'radix': 2, // http://eslint.org/docs/rules/radix - 'vars-on-top': 2, // http://eslint.org/docs/rules/vars-on-top - 'wrap-iife': [2, 'any'], // http://eslint.org/docs/rules/wrap-iife - 'yoda': 2, // http://eslint.org/docs/rules/yoda - - /** - * Style - */ - 'indent': [2, 2], // http://eslint.org/docs/rules/indent - 'brace-style': [ - 2, // http://eslint.org/docs/rules/brace-style - '1tbs', { - 'allowSingleLine': true - } - ], - 'quotes': [ - 2, 'single', 'avoid-escape' // http://eslint.org/docs/rules/quotes - ], - 'id-length': [2, { // http://eslint.org/docs/rules/id-length - 'min': 2, - 'properties': 'never' - }], - 'camelcase': [2, { // http://eslint.org/docs/rules/camelcase - 'properties': 'never' - }], - 'comma-spacing': [2, { // http://eslint.org/docs/rules/comma-spacing - 'before': false, - 'after': true - }], - 'comma-style': [2, 'last'], // http://eslint.org/docs/rules/comma-style - 'eol-last': 2, // http://eslint.org/docs/rules/eol-last - 'func-names': 1, // http://eslint.org/docs/rules/func-names - 'key-spacing': [2, { // http://eslint.org/docs/rules/key-spacing - 'beforeColon': false, - 'afterColon': true - }], - 'new-cap': [2, { // http://eslint.org/docs/rules/new-cap - 'newIsCap': true - }], - 'no-multiple-empty-lines': [2, { // http://eslint.org/docs/rules/no-multiple-empty-lines - 'max': 2 - }], - 'no-nested-ternary': 2, // http://eslint.org/docs/rules/no-nested-ternary - 'no-new-object': 2, // http://eslint.org/docs/rules/no-new-object - 'no-spaced-func': 2, // http://eslint.org/docs/rules/no-spaced-func - 'no-trailing-spaces': 2, // http://eslint.org/docs/rules/no-trailing-spaces - 'no-extra-parens': [2, 'functions'], // http://eslint.org/docs/rules/no-extra-parens - 'no-underscore-dangle': 0, // http://eslint.org/docs/rules/no-underscore-dangle - 'one-var': [2, 'never'], // http://eslint.org/docs/rules/one-var - 'padded-blocks': [2, 'never'], // http://eslint.org/docs/rules/padded-blocks - 'semi': [2, 'always'], // http://eslint.org/docs/rules/semi - 'semi-spacing': [2, { // http://eslint.org/docs/rules/semi-spacing - 'before': false, - 'after': true - }], - 'space-after-keywords': 2, // http://eslint.org/docs/rules/space-after-keywords - 'space-before-blocks': 2, // http://eslint.org/docs/rules/space-before-blocks - 'space-before-function-paren': [2, 'never'], // http://eslint.org/docs/rules/space-before-function-paren - 'space-infix-ops': 2, // http://eslint.org/docs/rules/space-infix-ops - 'space-return-throw-case': 2, // http://eslint.org/docs/rules/space-return-throw-case - 'spaced-comment': [2, 'always', {// http://eslint.org/docs/rules/spaced-comment - 'exceptions': ['-', '+'], - 'markers': ['=', '!'] // space here to support sprockets directives - }], - } -}; diff --git a/packages/eslint-config-airbnb/index.js b/packages/eslint-config-airbnb/index.js deleted file mode 100644 index 3cda9b0f9c..0000000000 --- a/packages/eslint-config-airbnb/index.js +++ /dev/null @@ -1,13 +0,0 @@ -const reactRules = require('./react'); -const base = require('./base'); - -// clone this so we aren't mutating a module -const eslintrc = JSON.parse(JSON.stringify(base)); - -// manually merge in React rules -eslintrc.plugins = reactRules.plugins; -Object.keys(reactRules.rules).forEach(function assignRule(ruleId) { - eslintrc.rules[ruleId] = reactRules.rules[ruleId]; -}); - -module.exports = eslintrc; diff --git a/packages/eslint-config-airbnb/node_modules/eslint-config-airbnb b/packages/eslint-config-airbnb/node_modules/eslint-config-airbnb deleted file mode 120000 index a96aa0ea9d..0000000000 --- a/packages/eslint-config-airbnb/node_modules/eslint-config-airbnb +++ /dev/null @@ -1 +0,0 @@ -.. \ No newline at end of file diff --git a/packages/eslint-config-airbnb/package.json b/packages/eslint-config-airbnb/package.json deleted file mode 100644 index 050567251f..0000000000 --- a/packages/eslint-config-airbnb/package.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "name": "eslint-config-airbnb", - "version": "0.0.8", - "description": "Airbnb's ESLint config, following our styleguide", - "main": "index.js", - "scripts": { - "lint": "./node_modules/.bin/eslint .", - "test": "./node_modules/.bin/babel-tape-runner ./test/test-*.js" - }, - "repository": { - "type": "git", - "url": "https://github.com/airbnb/javascript" - }, - "keywords": [ - "eslint", - "eslintconfig", - "config", - "airbnb", - "javascript", - "styleguide" - ], - "author": "Jake Teton-Landis (https://twitter.com/@jitl)", - "license": "MIT", - "bugs": { - "url": "https://github.com/airbnb/javascript/issues" - }, - "homepage": "https://github.com/airbnb/javascript", - "devDependencies": { - "babel-eslint": "4.0.10", - "babel-tape-runner": "1.2.0", - "eslint": "1.1.0", - "eslint-plugin-react": "3.2.3", - "react": "0.13.3", - "tape": "4.2.0" - } -} diff --git a/packages/eslint-config-airbnb/react.js b/packages/eslint-config-airbnb/react.js deleted file mode 100644 index a0ab17f396..0000000000 --- a/packages/eslint-config-airbnb/react.js +++ /dev/null @@ -1,36 +0,0 @@ -module.exports = { - 'plugins': [ - 'react' // https://github.com/yannickcr/eslint-plugin-react - ], - rules: { - /** - * JSX style - */ - 'react/display-name': 0, // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/display-name.md - 'react/jsx-boolean-value': 2, // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-boolean-value.md - 'react/jsx-quotes': [2, 'double'], // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-quotes.md - 'react/jsx-no-undef': 2, // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-undef.md - 'react/jsx-sort-props': 0, // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-sort-props.md - 'react/jsx-sort-prop-types': 0, // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-sort-prop-types.md - 'react/jsx-uses-react': 2, // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-uses-react.md - 'react/jsx-uses-vars': 2, // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-uses-vars.md - 'react/no-did-mount-set-state': [2, 'allow-in-func'], // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-did-mount-set-state.md - 'react/no-did-update-set-state': 2, // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-did-update-set-state.md - 'react/no-multi-comp': 2, // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-multi-comp.md - 'react/no-unknown-property': 2, // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-unknown-property.md - 'react/prop-types': 2, // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/prop-types.md - 'react/react-in-jsx-scope': 2, // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/react-in-jsx-scope.md - 'react/self-closing-comp': 2, // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/self-closing-comp.md - 'react/wrap-multilines': 2, // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/wrap-multilines.md - 'react/sort-comp': [2, { // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/sort-comp.md - 'order': [ - 'lifecycle', - '/^on.+$/', - '/^(get|set)(?!(InitialState$|DefaultProps$|ChildContext$)).+$/', - 'everything-else', - '/^render.+$/', - 'render' - ] - }] - } -}; diff --git a/packages/eslint-config-airbnb/test/test-base.js b/packages/eslint-config-airbnb/test/test-base.js deleted file mode 100644 index ecf06cdf58..0000000000 --- a/packages/eslint-config-airbnb/test/test-base.js +++ /dev/null @@ -1,13 +0,0 @@ -import test from 'tape'; -import base from '../base'; - -test('base: does not reference react', t => { - t.plan(2); - - t.notOk(base.plugins, 'plugins is unspecified'); - - // scan rules for react/ and fail if any exist - const reactRuleIds = Object.keys(base.rules) - .filter(ruleId => ruleId.indexOf('react/') === 0); - t.deepEquals(reactRuleIds, [], 'there are no react/ rules'); -}); diff --git a/packages/eslint-config-airbnb/test/test-react-order.js b/packages/eslint-config-airbnb/test/test-react-order.js deleted file mode 100644 index 9ef23f6737..0000000000 --- a/packages/eslint-config-airbnb/test/test-react-order.js +++ /dev/null @@ -1,83 +0,0 @@ -import test from 'tape'; -import { CLIEngine } from 'eslint'; -import eslintrc from '../'; - -const cli = new CLIEngine({ - useEslintrc: false, - baseConfig: eslintrc, -}); - -function lint(text) { - // @see http://eslint.org/docs/developer-guide/nodejs-api.html#executeonfiles - // @see http://eslint.org/docs/developer-guide/nodejs-api.html#executeontext - return cli.executeOnText(text).results[0]; -} - -function wrapComponent(body) { - return ` -import React from 'react'; -export default class MyComponent extends React.Component { -${body} -} -`; -} - -test('validate react prop order', t => { - t.test('make sure our eslintrc has React linting dependencies', t => { - t.plan(2); - t.equal(eslintrc.parser, 'babel-eslint', 'uses babel-eslint'); - t.equal(eslintrc.plugins[0], 'react', 'uses eslint-plugin-react'); - }); - - t.test('passes a good component', t => { - t.plan(3); - const result = lint(wrapComponent(` - componentWillMount() { } - componentDidMount() { } - setFoo() { } - getFoo() { } - setBar() { } - someMethod() { } - renderDogs() { } - render() { return
; } -`)); - - t.notOk(result.warningCount, 'no warnings'); - t.notOk(result.errorCount, 'no errors'); - t.deepEquals(result.messages, [], 'no messages in results'); - }); - - t.test('order: when random method is first', t => { - t.plan(2); - const result = lint(wrapComponent(` - someMethod() { } - componentWillMount() { } - componentDidMount() { } - setFoo() { } - getFoo() { } - setBar() { } - renderDogs() { } - render() { return
; } -`)); - - t.ok(result.errorCount, 'fails'); - t.equal(result.messages[0].ruleId, 'react/sort-comp', 'fails due to sort'); - }); - - t.test('order: when random method after lifecycle methods', t => { - t.plan(2); - const result = lint(wrapComponent(` - componentWillMount() { } - componentDidMount() { } - someMethod() { } - setFoo() { } - getFoo() { } - setBar() { } - renderDogs() { } - render() { return
; } -`)); - - t.ok(result.errorCount, 'fails'); - t.equal(result.messages[0].ruleId, 'react/sort-comp', 'fails due to sort'); - }); -}); diff --git a/react/README.md b/react/README.md index d1ce8c73da..b1d99d5ef6 100644 --- a/react/README.md +++ b/react/README.md @@ -1,12 +1,11 @@ -# Airbnb React/JSX Style Guide +# React/JSX Style Guide -*A mostly reasonable approach to React and JSX* +*A mostly reasonable approach to React and JSX, based on the Airbnb styleguide of the same name* ## Table of Contents 1. [Basic Rules](#basic-rules) 1. [Naming](#naming) - 1. [Declaration](#declaration) 1. [Alignment](#alignment) 1. [Quotes](#quotes) 1. [Spacing](#spacing) @@ -42,17 +41,33 @@ } ``` +## Export at the end of the file + + ```javascript + // bad + export default class Listing extends React.Component { + ... + } + + // good + class Listing extends React.Component { + ... + } + + export default Listing; + ``` + ## Naming - - **Extensions**: Use `.jsx` extension for React components. - - **Filename**: Use PascalCase for filenames. E.g., `ReservationCard.jsx`. + - **Extensions**: Use `.js` extension for React components. + - **Filename**: Use snake_case for filenames. E.g., `reservation_card.js`. - **Reference Naming**: Use PascalCase for React components and camelCase for their instances: ```javascript // bad - const reservationCard = require('./ReservationCard'); + const reservationCard = require('./reservation_card'); // good - const ReservationCard = require('./ReservationCard'); + const ReservationCard = require('./reservation_card'); // bad const ReservationItem = ; @@ -61,32 +76,16 @@ const reservationItem = ; ``` - **Component Naming**: Use the filename as the component name. For example, `ReservationCard.jsx` should have a reference name of `ReservationCard`. However, for root components of a directory, use `index.jsx` as the filename and use the directory name as the component name: + **Component Naming**: Use the filename as the component name. For example, `reservation_card.js` should have a reference name of `ReservationCard`. However, for root components of a directory, use `index.js` as the filename and use the directory name as the component name: ```javascript // bad - const Footer = require('./Footer/Footer.jsx') - - // bad - const Footer = require('./Footer/index.jsx') - - // good - const Footer = require('./Footer') - ``` - - -## Declaration - - Do not use displayName for naming components. Instead, name the component by reference. + const Footer = require('./footer/footer.js') - ```javascript // bad - export default React.createClass({ - displayName: 'ReservationCard', - // stuff goes here - }); + const Footer = require('./footer/index.js') - // good - export default class ReservationCard extends React.Component { - } + // good (note trailing slash) + const Footer = require('./footer/') ``` ## Alignment @@ -99,8 +98,8 @@ // good // if props fit in one line then keep it on the same line @@ -108,8 +107,8 @@ // children get indented normally @@ -153,14 +152,14 @@ ```javascript // bad // good ``` @@ -204,13 +203,13 @@ ```javascript // bad + bar = "bar" + baz = "baz" /> // good ``` @@ -259,18 +258,20 @@ ```javascript import React, { Component, PropTypes } from 'react'; + + const { number, string } = PropTypes; const propTypes = { - id: PropTypes.number.isRequired, - url: PropTypes.string.isRequired, - text: PropTypes.string, + id: number.isRequired, + url: string.isRequired, + text: string, }; const defaultProps = { text: 'Hello World', }; - export default class Link extends Component { + class Link extends Component { static methodsAreOk() { return true; } @@ -280,13 +281,14 @@ } } - Link.propTypes = propTypes; + Link.propTypes = propTypes; Link.defaultProps = defaultProps; + + export default Link; ``` - Ordering for React.createClass: - 1. displayName 1. propTypes 1. contextTypes 1. childContextTypes