diff --git a/README.md b/README.md
index 0ef940bf17..69571fd065 100644
--- a/README.md
+++ b/README.md
@@ -76,7 +76,9 @@
- [2.1](#2.1) Use `const` for all of your references; avoid using `var`.
- > Why? This ensures that you can't reassign your references (mutation), which can lead to bugs and difficult to comprehend code.
+ > Why? This ensures that you can't reassign your references, which can lead to bugs and difficult to comprehend code.
+
+ eslint rules: [`prefer-const`](http://eslint.org/docs/rules/prefer-const.html), [`no-const-assign`](http://eslint.org/docs/rules/no-const-assign.html).
```javascript
// bad
@@ -88,9 +90,11 @@
const b = 2;
```
- - [2.2](#2.2) If you must mutate references, use `let` instead of `var`.
+ - [2.2](#2.2) If you must reassign references, use `let` instead of `var`.
+
+ > Why? `let` is block-scoped rather than function-scoped like `var`.
- > Why? `let` is block-scoped rather than function-scoped like `var`.
+ eslint rules: [`no-var`](http://eslint.org/docs/rules/no-var.html).
```javascript
// bad
@@ -124,6 +128,8 @@
- [3.1](#3.1) Use the literal syntax for object creation.
+ eslint rules: [`no-new-object`](http://eslint.org/docs/rules/no-new-object.html).
+
```javascript
// bad
const item = new Object();
@@ -170,7 +176,7 @@
- [3.4](#3.4) Use computed property names when creating objects with dynamic property names.
- > Why? They allow you to define all the properties of an object in one place.
+ > Why? They allow you to define all the properties of an object in one place.
```javascript
@@ -196,6 +202,8 @@
- [3.5](#3.5) Use object method shorthand.
+ eslint rules: [`object-shorthand`](http://eslint.org/docs/rules/object-shorthand.html).
+
```javascript
// bad
const atom = {
@@ -219,7 +227,9 @@
- [3.6](#3.6) Use property value shorthand.
- > Why? It is shorter to write and descriptive.
+ > Why? It is shorter to write and descriptive.
+
+ eslint rules: [`object-shorthand`](http://eslint.org/docs/rules/object-shorthand.html).
```javascript
const lukeSkywalker = 'Luke Skywalker';
@@ -237,7 +247,7 @@
- [3.7](#3.7) Group your shorthand properties at the beginning 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.
```javascript
const anakinSkywalker = 'Anakin Skywalker';
@@ -264,12 +274,36 @@
};
```
+ - [3.8](#3.8) Only quote properties that are invalid identifiers.
+
+ > Why? In general we consider it subjectively easier to read. It improves syntax highlighting, and is also more easily optimized by many JS engines.
+
+ eslint rules: [`quote-props`](http://eslint.org/docs/rules/quote-props.html).
+
+ ```javascript
+ // bad
+ const bad = {
+ 'foo': 3,
+ 'bar': 4,
+ 'data-blah': 5,
+ };
+
+ // good
+ const good = {
+ foo: 3,
+ bar: 4,
+ 'data-blah': 5,
+ };
+ ```
+
**[⬆ back to top](#table-of-contents)**
## Arrays
- [4.1](#4.1) Use the literal syntax for array creation.
+ eslint rules: [`no-array-constructor`](http://eslint.org/docs/rules/no-array-constructor.html).
+
```javascript
// bad
const items = new Array();
@@ -319,7 +353,7 @@
- [5.1](#5.1) Use object destructuring when accessing and using multiple properties of an object.
- > Why? Destructuring saves you from creating temporary references for those properties.
+ > Why? Destructuring saves you from creating temporary references for those properties.
```javascript
// bad
@@ -331,8 +365,8 @@
}
// good
- function getFullName(obj) {
- const { firstName, lastName } = obj;
+ function getFullName(user) {
+ const { firstName, lastName } = user;
return `${firstName} ${lastName}`;
}
@@ -357,7 +391,7 @@
- [5.3](#5.3) Use object destructuring for multiple return values, not array destructuring.
- > Why? You can add new properties over time or change the order of things without breaking call sites.
+ > Why? You can add new properties over time or change the order of things without breaking call sites.
```javascript
// bad
@@ -386,6 +420,8 @@
- [6.1](#6.1) Use single quotes `''` for strings.
+ eslint rules: [`quotes`](http://eslint.org/docs/rules/quotes.html).
+
```javascript
// bad
const name = "Capt. Janeway";
@@ -394,7 +430,7 @@
const name = 'Capt. Janeway';
```
- - [6.2](#6.2) Strings longer than 100 characters should be written across multiple lines using string concatenation.
+ - [6.2](#6.2) Strings that cause the line to go over 100 characters should be written across multiple lines using string concatenation.
- [6.3](#6.3) Note: If overused, long strings with concatenation could impact performance. [jsPerf](http://jsperf.com/ya-string-concat) & [Discussion](https://github.com/airbnb/javascript/issues/40).
```javascript
@@ -416,7 +452,9 @@
- [6.4](#6.4) When programmatically building up strings, use template strings instead of concatenation.
- > Why? Template strings give you a readable, concise syntax with proper newlines and string interpolation features.
+ > Why? Template strings give you a readable, concise syntax with proper newlines and string interpolation features.
+
+ eslint rules: [`prefer-template`](http://eslint.org/docs/rules/prefer-template.html).
```javascript
// bad
@@ -434,7 +472,7 @@
return `How are you, ${name}?`;
}
```
- - [6.5](#6.5) Never use eval() on a string, it opens too many vulnerabilities.
+ - [6.5](#6.5) Never use `eval()` on a string, it opens too many vulnerabilities.
**[⬆ back to top](#table-of-contents)**
@@ -443,7 +481,7 @@
- [7.1](#7.1) Use function declarations instead of function expressions.
- > Why? Function declarations are named, so they're easier to identify in call stacks. Also, the whole body of a function declaration is hoisted, whereas only the reference of a function expression is hoisted. This rule makes it possible to always use [Arrow Functions](#arrow-functions) in place of function expressions.
+ > Why? Function declarations are named, so they're easier to identify in call stacks. Also, the whole body of a function declaration is hoisted, whereas only the reference of a function expression is hoisted. This rule makes it possible to always use [Arrow Functions](#arrow-functions) in place of function expressions.
```javascript
// bad
@@ -465,6 +503,7 @@
```
- [7.3](#7.3) Never declare a function in a non-function block (if, while, etc). Assign the function to a variable instead. Browsers will allow you to do it, but they all interpret it differently, which is bad news bears.
+
- [7.4](#7.4) **Note:** ECMA-262 defines a `block` as a list of statements. A function declaration is not a statement. [Read ECMA-262's note on this issue](http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf#page=97).
```javascript
@@ -501,7 +540,7 @@
- [7.6](#7.6) Never use `arguments`, opt to use rest syntax `...` instead.
- > Why? `...` is explicit about which arguments you want pulled. Plus rest arguments are a real Array and not Array-like like `arguments`.
+ > Why? `...` is explicit about which arguments you want pulled. Plus rest arguments are a real Array and not Array-like like `arguments`.
```javascript
// bad
@@ -545,19 +584,19 @@
- [7.8](#7.8) Avoid side effects with default parameters.
- > Why? They are confusing to reason about.
+ > Why? They are confusing to reason about.
- ```javascript
- var b = 1;
- // bad
- function count(a = b++) {
- console.log(a);
- }
- count(); // 1
- count(); // 2
- count(3); // 3
- count(); // 3
- ```
+ ```javascript
+ var b = 1;
+ // bad
+ function count(a = b++) {
+ console.log(a);
+ }
+ count(); // 1
+ count(); // 2
+ count(3); // 3
+ count(); // 3
+ ```
- [7.9](#7.9) Always put default parameters last.
@@ -573,17 +612,75 @@
}
```
-- [7.10](#7.10) Never use the Function constructor to create a new function.
+ - [7.10](#7.10) Never use the Function constructor to create a new function.
- > Why? Creating a function in this way evaluates a string similarly to eval(), which opens vulnerabilities.
+ > Why? Creating a function in this way evaluates a string similarly to eval(), which opens vulnerabilities.
- ```javascript
- // bad
- var add = new Function('a', 'b', 'return a + b');
+ ```javascript
+ // bad
+ var add = new Function('a', 'b', 'return a + b');
- // still bad
- var subtract = Function('a', 'b', 'return a - b');
- ```
+ // still bad
+ var subtract = Function('a', 'b', 'return a - b');
+ ```
+
+ - [7.11](#7.11) Spacing in a function signature.
+
+ > Why? Consistency is good, and you shouldn’t have to add or remove a space when adding or removing a name.
+
+ ```javascript
+ // bad
+ const f = function(){};
+ const g = function (){};
+ const h = function() {};
+
+ // good
+ const x = function () {};
+ const y = function a() {};
+ ```
+
+ - [7.12](#7.12) Never mutate parameters.
+
+ > Why? Manipulating objects passed in as parameters can cause unwanted variable side effects in the original caller.
+
+ eslint rules: [`no-param-reassign`](http://eslint.org/docs/rules/no-param-reassign.html).
+
+ ```javascript
+ // bad
+ function f1(obj) {
+ obj.key = 1;
+ };
+
+ // good
+ function f2(obj) {
+ const key = Object.prototype.hasOwnProperty.call(obj, 'key') ? obj.key : 1;
+ };
+ ```
+
+ - [7.13](#7.13) Never reassign parameters.
+
+ > Why? Reassigning parameters can lead to unexpected behavior, especially when accessing the `arguments` object. It can also cause optimization issues, especially in V8.
+
+ eslint rules: [`no-param-reassign`](http://eslint.org/docs/rules/no-param-reassign.html).
+
+ ```javascript
+ // bad
+ function f1(a) {
+ a = 1;
+ }
+
+ function f2(a) {
+ if (!a) { a = 1; }
+ }
+
+ // good
+ function f3(a) {
+ const b = a || 1;
+ }
+
+ function f4(a = 1) {
+ }
+ ```
**[⬆ back to top](#table-of-contents)**
@@ -591,9 +688,11 @@
- [8.1](#8.1) When you must use function expressions (as when passing an anonymous function), use arrow function notation.
- > Why? It creates a version of the function that executes in the context of `this`, which is usually what you want, and is a more concise syntax.
+ > Why? It creates a version of the function that executes in the context of `this`, which is usually what you want, and is a more concise syntax.
+
+ > Why not? If you have a fairly complicated function, you might move that logic out into its own function declaration.
- > Why not? If you have a fairly complicated function, you might move that logic out into its own function declaration.
+ eslint rules: [`prefer-arrow-callback`](http://eslint.org/docs/rules/prefer-arrow-callback.html), [`arrow-spacing`](http://eslint.org/docs/rules/arrow-spacing.html).
```javascript
// bad
@@ -609,11 +708,13 @@
});
```
- - [8.2](#8.2) If the function body consists of a single expression, feel free to omit the braces and use the implicit return. Otherwise use a `return` statement.
+ - [8.2](#8.2) If the function body consists of a single expression, omit the braces and use the implicit return. Otherwise, keep the braces and use a `return` statement.
- > Why? Syntactic sugar. It reads well when multiple functions are chained together.
+ > Why? Syntactic sugar. It reads well when multiple functions are chained together.
- > Why not? If you plan on returning an object.
+ > Why not? If you plan on returning an object.
+
+ eslint rules: [`arrow-parens`](http://eslint.org/docs/rules/arrow-parens.html), [`arrow-body-style`](http://eslint.org/docs/rules/arrow-body-style.html).
```javascript
// good
@@ -634,7 +735,7 @@
- [8.3](#8.3) In case the expression spans over multiple lines, wrap it in parentheses for better readability.
- > Why? It shows clearly where the function starts and ends.
+ > Why? It shows clearly where the function starts and ends.
```js
// bad
@@ -651,16 +752,36 @@
```
- - [8.4](#8.4) If your function only takes a single argument, feel free to omit the parentheses.
+ - [8.4](#8.4) If your function takes a single argument and doesn’t use braces, omit the parentheses. Otherwise, always include parentheses around arguments.
+
+ > Why? Less visual clutter.
- > Why? Less visual clutter.
+ eslint rules: [`arrow-parens`](http://eslint.org/docs/rules/arrow-parens.html).
```js
+ // bad
+ [1, 2, 3].map((x) => x * x);
+
// good
[1, 2, 3].map(x => x * x);
// good
- [1, 2, 3].reduce((y, x) => x + y);
+ [1, 2, 3].map(number => (
+ `A long string with the ${number}. It’s so long that we’ve broken it ` +
+ 'over multiple lines!'
+ ));
+
+ // bad
+ [1, 2, 3].map(x => {
+ const y = x + 1;
+ return x * y;
+ });
+
+ // good
+ [1, 2, 3].map((x) => {
+ const y = x + 1;
+ return x * y;
+ });
```
**[⬆ back to top](#table-of-contents)**
@@ -670,14 +791,14 @@
- [9.1](#9.1) Always use `class`. Avoid manipulating `prototype` directly.
- > Why? `class` syntax is more concise and easier to reason about.
+ > Why? `class` syntax is more concise and easier to reason about.
```javascript
// bad
function Queue(contents = []) {
this._queue = [...contents];
}
- Queue.prototype.pop = function() {
+ Queue.prototype.pop = function () {
const value = this._queue[0];
this._queue.splice(0, 1);
return value;
@@ -699,7 +820,7 @@
- [9.2](#9.2) Use `extends` for inheritance.
- > Why? It is a built-in way to inherit prototype functionality without breaking `instanceof`.
+ > Why? It is a built-in way to inherit prototype functionality without breaking `instanceof`.
```javascript
// bad
@@ -708,7 +829,7 @@
Queue.apply(this, contents);
}
inherits(PeekableQueue, Queue);
- PeekableQueue.prototype.peek = function() {
+ PeekableQueue.prototype.peek = function () {
return this._queue[0];
}
@@ -724,12 +845,12 @@
```javascript
// bad
- Jedi.prototype.jump = function() {
+ Jedi.prototype.jump = function () {
this.jumping = true;
return true;
};
- Jedi.prototype.setHeight = function(height) {
+ Jedi.prototype.setHeight = function (height) {
this.height = height;
};
@@ -782,7 +903,7 @@
- [10.1](#10.1) Always use modules (`import`/`export`) over a non-standard module system. You can always transpile to your preferred module system.
- > Why? Modules are the future, let's start using the future now.
+ > Why? Modules are the future, let's start using the future now.
```javascript
// bad
@@ -800,7 +921,7 @@
- [10.2](#10.2) Do not use wildcard imports.
- > Why? This makes sure you have a single default export.
+ > Why? This makes sure you have a single default export.
```javascript
// bad
@@ -812,7 +933,7 @@
- [10.3](#10.3) And do not export directly from an import.
- > Why? Although the one-liner is concise, having one clear way to import and one clear way to export makes things consistent.
+ > Why? Although the one-liner is concise, having one clear way to import and one clear way to export makes things consistent.
```javascript
// bad
@@ -831,7 +952,9 @@
- [11.1](#11.1) Don't use iterators. Prefer JavaScript's higher-order functions like `map()` and `reduce()` instead of loops like `for-of`.
- > Why? This enforces our immutable rule. Dealing with pure functions that return values is easier to reason about than side-effects.
+ > Why? This enforces our immutable rule. Dealing with pure functions that return values is easier to reason about than side-effects.
+
+ eslint rules: [`no-iterator`](http://eslint.org/docs/rules/no-iterator.html).
```javascript
const numbers = [1, 2, 3, 4, 5];
@@ -856,7 +979,7 @@
- [11.2](#11.2) Don't use generators for now.
- > Why? They don't transpile well to ES5.
+ > Why? They don't transpile well to ES5.
**[⬆ back to top](#table-of-contents)**
@@ -865,6 +988,8 @@
- [12.1](#12.1) Use dot notation when accessing properties.
+ eslint rules: [`dot-notation`](http://eslint.org/docs/rules/dot-notation.html).
+
```javascript
const luke = {
jedi: true,
@@ -912,6 +1037,8 @@
> Why? It's easier to add new variable declarations this way, and you never have to worry about swapping out a `;` for a `,` or introducing punctuation-only diffs.
+ eslint rules: [`one-var`](http://eslint.org/docs/rules/one-var.html).
+
```javascript
// bad
const items = getItems(),
@@ -932,7 +1059,7 @@
- [13.3](#13.3) Group all your `const`s and then group all your `let`s.
- > Why? This is helpful when later on you might need to assign a variable depending on one of the previous assigned variables.
+ > Why? This is helpful when later on you might need to assign a variable depending on one of the previous assigned variables.
```javascript
// bad
@@ -957,11 +1084,11 @@
- [13.4](#13.4) Assign variables where you need them, but place them in a reasonable place.
- > Why? `let` and `const` are block scoped and not function scoped.
+ > Why? `let` and `const` are block scoped and not function scoped.
```javascript
// good
- function() {
+ function () {
test();
console.log('doing stuff..');
@@ -977,7 +1104,7 @@
}
// bad - unnecessary function call
- function(hasName) {
+ function (hasName) {
const name = getName();
if (!hasName) {
@@ -990,7 +1117,7 @@
}
// good
- function(hasName) {
+ function (hasName) {
if (!hasName) {
return false;
}
@@ -1050,7 +1177,7 @@
anonymous(); // => TypeError anonymous is not a function
- var anonymous = function() {
+ var anonymous = function () {
console.log('anonymous function expression');
};
}
@@ -1096,7 +1223,7 @@
}
```
- - For more information refer to [JavaScript Scoping & Hoisting](http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting) by [Ben Cherry](http://www.adequatelygood.com/).
+ - For more information refer to [JavaScript Scoping & Hoisting](http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting/) by [Ben Cherry](http://www.adequatelygood.com/).
**[⬆ back to top](#table-of-contents)**
@@ -1104,8 +1231,11 @@
## Comparison Operators & Equality
- [15.1](#15.1) Use `===` and `!==` over `==` and `!=`.
+
- [15.2](#15.2) Conditional statements such as the `if` statement evaluate their expression using coercion with the `ToBoolean` abstract method and always follow these simple rules:
+ eslint rules: [`eqeqeq`](http://eslint.org/docs/rules/eqeqeq.html).
+
+ **Objects** evaluate to **true**
+ **Undefined** evaluates to **false**
+ **Null** evaluates to **false**
@@ -1167,10 +1297,10 @@
}
// bad
- function() { return false; }
+ function () { return false; }
// good
- function() {
+ function () {
return false;
}
```
@@ -1178,6 +1308,8 @@
- [16.2](#16.2) If you're using multi-line blocks with `if` and `else`, put `else` on the same line as your
`if` block's closing brace.
+ eslint rules: [`brace-style`](http://eslint.org/docs/rules/brace-style.html).
+
```javascript
// bad
if (test) {
@@ -1235,7 +1367,7 @@
}
```
- - [17.2](#17.2) Use `//` for single line comments. Place single line comments on a newline above the subject of the comment. Put an empty line before the comment.
+ - [17.2](#17.2) Use `//` for single line comments. Place single line comments on a newline above the subject of the comment. Put an empty line before the comment unless it's on the first line of a block.
```javascript
// bad
@@ -1263,6 +1395,14 @@
return type;
}
+
+ // also good
+ function getType() {
+ // set the default type to 'no type'
+ const type = this._type || 'no type';
+
+ return type;
+ }
```
- [17.3](#17.3) Prefixing your comments with `FIXME` or `TODO` helps other developers quickly understand if you're pointing out a problem that needs to be revisited, or if you're suggesting a solution to the problem that needs to be implemented. These are different than regular comments because they are actionable. The actions are `FIXME -- need to figure this out` or `TODO -- need to implement`.
@@ -1300,25 +1440,29 @@
- [18.1](#18.1) Use soft tabs set to 2 spaces.
+ eslint rules: [`indent`](http://eslint.org/docs/rules/indent.html).
+
```javascript
// bad
- function() {
+ function () {
∙∙∙∙const name;
}
// bad
- function() {
+ function () {
∙const name;
}
// good
- function() {
+ function () {
∙∙const name;
}
```
- [18.2](#18.2) Place 1 space before the leading brace.
+ eslint rules: [`space-before-blocks`](http://eslint.org/docs/rules/space-before-blocks.html).
+
```javascript
// bad
function test(){
@@ -1343,7 +1487,9 @@
});
```
- - [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.). Place no space between the argument list and the function name in function calls and declarations.
+
+ eslint rules: [`space-after-keywords`](http://eslint.org/docs/rules/space-after-keywords.html), [`space-before-keywords`](http://eslint.org/docs/rules/space-before-keywords.html).
```javascript
// bad
@@ -1369,6 +1515,8 @@
- [18.4](#18.4) Set off operators with spaces.
+ eslint rules: [`space-infix-ops`](http://eslint.org/docs/rules/space-infix-ops.html).
+
```javascript
// bad
const x=y+5;
@@ -1381,14 +1529,14 @@
```javascript
// bad
- (function(global) {
+ (function (global) {
// ...stuff...
})(this);
```
```javascript
// bad
- (function(global) {
+ (function (global) {
// ...stuff...
})(this);↵
↵
@@ -1396,7 +1544,7 @@
```javascript
// good
- (function(global) {
+ (function (global) {
// ...stuff...
})(this);↵
```
@@ -1498,6 +1646,118 @@
return arr;
```
+ - [18.8](#18.8) Do not pad your blocks with blank lines.
+
+ eslint rules: [`padded-blocks`](http://eslint.org/docs/rules/padded-blocks.html).
+
+ ```javascript
+ // bad
+ function bar() {
+
+ console.log(foo);
+
+ }
+
+ // also bad
+ if (baz) {
+
+ console.log(qux);
+ } else {
+ console.log(foo);
+
+ }
+
+ // good
+ function bar() {
+ console.log(foo);
+ }
+
+ // good
+ if (baz) {
+ console.log(qux);
+ } else {
+ console.log(foo);
+ }
+ ```
+
+ - [18.9](#18.9) Do not add spaces inside parentheses.
+
+ eslint rules: [`space-in-parens`](http://eslint.org/docs/rules/space-in-parens.html).
+
+ ```javascript
+ // bad
+ function bar( foo ) {
+ return foo;
+ }
+
+ // good
+ function bar(foo) {
+ return foo;
+ }
+
+ // bad
+ if ( foo ) {
+ console.log(foo);
+ }
+
+ // good
+ if (foo) {
+ console.log(foo);
+ }
+ ```
+
+ - [18.10](#18.10) Do not add spaces inside brackets.
+
+ eslint rules: [`array-bracket-spacing`](http://eslint.org/docs/rules/array-bracket-spacing.html).
+
+ ```javascript
+ // bad
+ const foo = [ 1, 2, 3 ];
+ console.log(foo[ 0 ]);
+
+ // good
+ const foo = [1, 2, 3];
+ console.log(foo[0]);
+ ```
+
+ - [18.11](#18.11) Add spaces inside curly braces.
+
+ eslint rules: [`object-curly-spacing`](http://eslint.org/docs/rules/object-curly-spacing.html).
+
+ ```javascript
+ // bad
+ const foo = {clark: 'kent'};
+
+ // good
+ const foo = { clark: 'kent' };
+ ```
+
+ - [18.12](#18.12) Avoid having lines of code that are longer than 100 characters (including whitespace).
+
+ > Why? This ensures readability and maintainability.
+
+ eslint rules: [`max-len`](http://eslint.org/docs/rules/max-len.html).
+
+ ```javascript
+ // bad
+ const foo = 'Whatever national crop flips the window. The cartoon reverts within the screw. Whatever wizard constrains a helpful ally. The counterpart ascends!';
+
+ // bad
+ $.ajax({ method: 'POST', url: 'https://airbnb.com/', data: { name: 'John' } }).done(() => console.log('Congratulations!')).fail(() => console.log('You have failed this city.'));
+
+ // good
+ const foo = 'Whatever national crop flips the window. The cartoon reverts within the screw. ' +
+ 'Whatever wizard constrains a helpful ally. The counterpart ascends!';
+
+ // good
+ $.ajax({
+ method: 'POST',
+ url: 'https://airbnb.com/',
+ data: { name: 'John' },
+ })
+ .done(() => console.log('Congratulations!'))
+ .fail(() => console.log('You have failed this city.'));
+ ```
**[⬆ back to top](#table-of-contents)**
@@ -1505,6 +1765,8 @@
- [19.1](#19.1) Leading commas: **Nope.**
+ eslint rules: [`comma-style`](http://eslint.org/docs/rules/comma-style.html).
+
```javascript
// bad
const story = [
@@ -1539,7 +1801,9 @@
- [19.2](#19.2) Additional trailing comma: **Yup.**
- > Why? This leads to cleaner git diffs. Also, transpilers like Babel will remove the additional trailing comma in the transpiled code which means you don't have to worry about the [trailing comma problem](es5/README.md#commas) in legacy browsers.
+ eslint rules: [`comma-dangle`](http://eslint.org/docs/rules/comma-dangle.html).
+
+ > Why? This leads to cleaner git diffs. Also, transpilers like Babel will remove the additional trailing comma in the transpiled code which means you don't have to worry about the [trailing comma problem](es5/README.md#commas) in legacy browsers.
```javascript
// bad - git diff without trailing comma
@@ -1587,9 +1851,11 @@
- [20.1](#20.1) **Yup.**
+ eslint rules: [`semi`](http://eslint.org/docs/rules/semi.html).
+
```javascript
// bad
- (function() {
+ (function () {
const name = 'Skywalker'
return name
})()
@@ -1607,7 +1873,7 @@
})();
```
- [Read more](http://stackoverflow.com/a/7365214/1712802).
+ [Read more](http://stackoverflow.com/questions/7365172/semicolon-before-self-invoking-function/7365214%237365214).
**[⬆ back to top](#table-of-contents)**
@@ -1627,7 +1893,9 @@
const totalScore = String(this.reviewScore);
```
- - [21.3](#21.3) Use `parseInt` for Numbers and always with a radix for type casting.
+ - [21.3](#21.3) Numbers: Use `Number` for type casting and `parseInt` always with a radix for parsing strings.
+
+ eslint rules: [`radix`](http://eslint.org/docs/rules/radix).
```javascript
const inputValue = '4';
@@ -1707,6 +1975,8 @@
- [22.2](#22.2) Use camelCase when naming objects, functions, and instances.
+ eslint rules: [`camelcase`](http://eslint.org/docs/rules/camelcase.html).
+
```javascript
// bad
const OBJEcttsssss = {};
@@ -1744,6 +2014,8 @@
- [22.4](#22.4) Use a leading underscore `_` when naming private properties.
+ eslint rules: [`no-underscore-dangle`](http://eslint.org/docs/rules/no-underscore-dangle.html).
+
```javascript
// bad
this.__firstName__ = 'Panda';
@@ -1759,7 +2031,7 @@
// bad
function foo() {
const self = this;
- return function() {
+ return function () {
console.log(self);
};
}
@@ -1767,7 +2039,7 @@
// bad
function foo() {
const that = this;
- return function() {
+ return function () {
console.log(that);
};
}
@@ -1781,6 +2053,7 @@
```
- [22.6](#22.6) If your file exports a single class, your filename should be exactly the name of the class.
+
```javascript
// file contents
class CheckBox {
@@ -1888,7 +2161,7 @@
...
- $(this).on('listingUpdated', function(e, listingId) {
+ $(this).on('listingUpdated', function (e, listingId) {
// do something with listingId
});
```
@@ -1901,7 +2174,7 @@
...
- $(this).on('listingUpdated', function(e, data) {
+ $(this).on('listingUpdated', function (e, data) {
// do something with data.listingId
});
```
@@ -1976,7 +2249,7 @@
## ECMAScript 5 Compatibility
- - [26.1](#26.1) Refer to [Kangax](https://twitter.com/kangax/)'s ES5 [compatibility table](http://kangax.github.com/es5-compat-table/).
+ - [26.1](#26.1) Refer to [Kangax](https://twitter.com/kangax/)'s ES5 [compatibility table](http://kangax.github.io/es5-compat-table/).
**[⬆ back to top](#table-of-contents)**
@@ -2002,20 +2275,28 @@
## Testing
- - [28.1](#28.1) **Yup.**
+ - [28.1](#28.1) **Yup.**
```javascript
- function() {
+ function () {
return true;
}
```
+ - [28.2](#28.2) **No, but seriously**:
+ - Whichever testing framework you use, you should be writing tests!
+ - Strive to write many small pure functions, and minimize where mutations occur.
+ - Be cautious about stubs and mocks - they can make your tests more brittle.
+ - We primarily use [`mocha`](https://www.npmjs.com/package/mocha) at Airbnb. [`tape`](https://www.npmjs.com/package/tape) is also used occasionally for small, separate modules.
+ - 100% test coverage is a good goal to strive for, even if it's not always practical to reach it.
+ - Whenever you fix a bug, _write a regression test_. A bug fixed without a regression test is almost certainly going to break again in the future.
+
**[⬆ back to top](#table-of-contents)**
## Performance
- - [On Layout & Web Performance](http://kellegous.com/j/2013/01/26/layout-performance/)
+ - [On Layout & Web Performance](http://www.kellegous.com/j/2013/01/26/layout-performance/)
- [String vs Array Concat](http://jsperf.com/string-vs-array-concat/2)
- [Try/Catch Cost In a Loop](http://jsperf.com/try-catch-in-loop-cost)
- [Bang Function](http://jsperf.com/bang-function)
@@ -2044,18 +2325,18 @@
- Code Style Linters
+ [ESlint](http://eslint.org/) - [Airbnb Style .eslintrc](https://github.com/airbnb/javascript/blob/master/linters/.eslintrc)
- + [JSHint](http://www.jshint.com/) - [Airbnb Style .jshintrc](https://github.com/airbnb/javascript/blob/master/linters/jshintrc)
+ + [JSHint](http://jshint.com/) - [Airbnb Style .jshintrc](https://github.com/airbnb/javascript/blob/master/linters/.jshintrc)
+ [JSCS](https://github.com/jscs-dev/node-jscs) - [Airbnb Style Preset](https://github.com/jscs-dev/node-jscs/blob/master/presets/airbnb.json)
**Other Style Guides**
- [Google JavaScript Style Guide](http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml)
- - [jQuery Core Style Guidelines](http://docs.jquery.com/JQuery_Core_Style_Guidelines)
- - [Principles of Writing Consistent, Idiomatic JavaScript](https://github.com/rwldrn/idiomatic.js/)
+ - [jQuery Core Style Guidelines](http://contribute.jquery.org/style-guide/js/)
+ - [Principles of Writing Consistent, Idiomatic JavaScript](https://github.com/rwaldron/idiomatic.js)
**Other Styles**
- - [Naming this in nested functions](https://gist.github.com/4135065) - Christian Johansen
+ - [Naming this in nested functions](https://gist.github.com/cjohansen/4135065) - Christian Johansen
- [Conditional Callbacks](https://github.com/airbnb/javascript/issues/52) - Ross Allen
- [Popular JavaScript Coding Conventions on Github](http://sideeffect.kr/popularconvention/#javascript) - JeongHoon Byun
- [Multiple var statements in JavaScript, not superfluous](http://benalman.com/news/2012/05/multiple-var-statements-javascript/) - Ben Alman
@@ -2082,7 +2363,7 @@
- [Human JavaScript](http://humanjavascript.com/) - Henrik Joreteg
- [Superhero.js](http://superherojs.com/) - Kim Joar Bekkelund, Mads Mobæk, & Olav Bjorkoy
- [JSBooks](http://jsbooks.revolunet.com/) - Julien Bouquillon
- - [Third Party JavaScript](http://manning.com/vinegar/) - Ben Vinegar and Anton Kovalyov
+ - [Third Party JavaScript](https://www.manning.com/books/third-party-javascript) - Ben Vinegar and Anton Kovalyov
- [Effective JavaScript: 68 Specific Ways to Harness the Power of JavaScript](http://amzn.com/0321812182) - David Herman
- [Eloquent JavaScript](http://eloquentjavascript.net/) - Marijn Haverbeke
- [You Don't Know JS: ES6 & Beyond](http://shop.oreilly.com/product/0636920033769.do) - Kyle Simpson
@@ -2092,18 +2373,18 @@
- [DailyJS](http://dailyjs.com/)
- [JavaScript Weekly](http://javascriptweekly.com/)
- [JavaScript, JavaScript...](http://javascriptweblog.wordpress.com/)
- - [Bocoup Weblog](http://weblog.bocoup.com/)
+ - [Bocoup Weblog](https://bocoup.com/weblog)
- [Adequately Good](http://www.adequatelygood.com/)
- - [NCZOnline](http://www.nczonline.net/)
+ - [NCZOnline](https://www.nczonline.net/)
- [Perfection Kills](http://perfectionkills.com/)
- [Ben Alman](http://benalman.com/)
- [Dmitry Baranovskiy](http://dmitry.baranovskiy.com/)
- [Dustin Diaz](http://dustindiaz.com/)
- - [nettuts](http://net.tutsplus.com/?s=javascript)
+ - [nettuts](http://code.tutsplus.com/?s=javascript)
**Podcasts**
- - [JavaScript Jabber](http://devchat.tv/js-jabber/)
+ - [JavaScript Jabber](https://devchat.tv/js-jabber/)
**[⬆ back to top](#table-of-contents)**
@@ -2118,12 +2399,15 @@
- **Apartmint**: [apartmint/javascript](https://github.com/apartmint/javascript)
- **Avalara**: [avalara/javascript](https://github.com/avalara/javascript)
- **Billabong**: [billabong/javascript](https://github.com/billabong/javascript)
+ - **Bisk**: [bisk/javascript](https://github.com/Bisk/javascript/)
- **Blendle**: [blendle/javascript](https://github.com/blendle/javascript)
- - **ComparaOnline**: [comparaonline/javascript](https://github.com/comparaonline/javascript)
+ - **ComparaOnline**: [comparaonline/javascript](https://github.com/comparaonline/javascript-style-guide)
- **Compass Learning**: [compasslearning/javascript-style-guide](https://github.com/compasslearning/javascript-style-guide)
- **DailyMotion**: [dailymotion/javascript](https://github.com/dailymotion/javascript)
- **Digitpaint** [digitpaint/javascript](https://github.com/digitpaint/javascript)
+ - **Ecosia**: [ecosia/javascript](https://github.com/ecosia/javascript)
- **Evernote**: [evernote/javascript-style-guide](https://github.com/evernote/javascript-style-guide)
+ - **Evolution Gaming**: [evolution-gaming/javascript](https://github.com/evolution-gaming/javascript)
- **ExactTarget**: [ExactTarget/javascript](https://github.com/ExactTarget/javascript)
- **Expensify** [Expensify/Style-Guide](https://github.com/Expensify/Style-Guide/blob/master/javascript.md)
- **Flexberry**: [Flexberry/javascript-style-guide](https://github.com/Flexberry/javascript-style-guide)
@@ -2131,13 +2415,16 @@
- **General Electric**: [GeneralElectric/javascript](https://github.com/GeneralElectric/javascript)
- **GoodData**: [gooddata/gdc-js-style](https://github.com/gooddata/gdc-js-style)
- **Grooveshark**: [grooveshark/javascript](https://github.com/grooveshark/javascript)
- - **How About We**: [howaboutwe/javascript](https://github.com/howaboutwe/javascript)
+ - **How About We**: [howaboutwe/javascript](https://github.com/howaboutwe/javascript-style-guide)
- **Huballin**: [huballin/javascript](https://github.com/huballin/javascript)
+ - **HubSpot**: [HubSpot/javascript](https://github.com/HubSpot/javascript)
+ - **Hyper**: [hyperoslo/javascript-playbook](https://github.com/hyperoslo/javascript-playbook/blob/master/style.md)
- **InfoJobs**: [InfoJobs/JavaScript-Style-Guide](https://github.com/InfoJobs/JavaScript-Style-Guide)
- **Intent Media**: [intentmedia/javascript](https://github.com/intentmedia/javascript)
- **Jam3**: [Jam3/Javascript-Code-Conventions](https://github.com/Jam3/Javascript-Code-Conventions)
+ - **JeopardyBot**: [kesne/jeopardy-bot](https://github.com/kesne/jeopardy-bot/blob/master/STYLEGUIDE.md)
- **JSSolutions**: [JSSolutions/javascript](https://github.com/JSSolutions/javascript)
- - **Kinetica Solutions**: [kinetica/javascript](https://github.com/kinetica/javascript)
+ - **Kinetica Solutions**: [kinetica/javascript](https://github.com/kinetica/Javascript-style-guide)
- **Mighty Spring**: [mightyspring/javascript](https://github.com/mightyspring/javascript)
- **MinnPost**: [MinnPost/javascript](https://github.com/MinnPost/javascript)
- **MitocGroup**: [MitocGroup/javascript](https://github.com/MitocGroup/javascript)
@@ -2148,15 +2435,17 @@
- **National Park Service**: [nationalparkservice/javascript](https://github.com/nationalparkservice/javascript)
- **Nimbl3**: [nimbl3/javascript](https://github.com/nimbl3/javascript)
- **Orion Health**: [orionhealth/javascript](https://github.com/orionhealth/javascript)
+ - **OutBoxSoft**: [OutBoxSoft/javascript](https://github.com/OutBoxSoft/javascript)
- **Peerby**: [Peerby/javascript](https://github.com/Peerby/javascript)
- **Razorfish**: [razorfish/javascript-style-guide](https://github.com/razorfish/javascript-style-guide)
- **reddit**: [reddit/styleguide/javascript](https://github.com/reddit/styleguide/tree/master/javascript)
+ - **React**: [/facebook/react/blob/master/CONTRIBUTING.md#style-guide](https://github.com/facebook/react/blob/master/CONTRIBUTING.md#style-guide)
- **REI**: [reidev/js-style-guide](https://github.com/reidev/js-style-guide)
- **Ripple**: [ripple/javascript-style-guide](https://github.com/ripple/javascript-style-guide)
- **SeekingAlpha**: [seekingalpha/javascript-style-guide](https://github.com/seekingalpha/javascript-style-guide)
- **Shutterfly**: [shutterfly/javascript](https://github.com/shutterfly/javascript)
- **Springload**: [springload/javascript](https://github.com/springload/javascript)
- - **StudentSphere**: [studentsphere/javascript](https://github.com/studentsphere/javascript)
+ - **StudentSphere**: [studentsphere/javascript](https://github.com/studentsphere/guide-javascript)
- **Target**: [target/javascript](https://github.com/target/javascript)
- **TheLadders**: [TheLadders/javascript](https://github.com/TheLadders/javascript)
- **T4R Technology**: [T4R-Technology/javascript](https://github.com/T4R-Technology/javascript)
diff --git a/linters/jshintrc b/linters/.jshintrc
similarity index 95%
rename from linters/jshintrc
rename to linters/.jshintrc
index 141067fd23..4d3468cb21 100644
--- a/linters/jshintrc
+++ b/linters/.jshintrc
@@ -34,8 +34,8 @@
// Prohibit use of a variable before it is defined.
"latedef": true,
- // Enforce line length to 80 characters
- "maxlen": 80,
+ // Enforce line length to 100 characters
+ "maxlen": 100,
// Require capitalized names for constructor functions.
"newcap": true,
diff --git a/packages/eslint-config-airbnb/.eslintrc b/packages/eslint-config-airbnb/.eslintrc
index cbf450f01f..4b3b1fa429 100644
--- a/packages/eslint-config-airbnb/.eslintrc
+++ b/packages/eslint-config-airbnb/.eslintrc
@@ -3,9 +3,6 @@
"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
+ "comma-dangle": 0
}
}
diff --git a/packages/eslint-config-airbnb/CHANGELOG.md b/packages/eslint-config-airbnb/CHANGELOG.md
new file mode 100644
index 0000000000..0cbe0e1357
--- /dev/null
+++ b/packages/eslint-config-airbnb/CHANGELOG.md
@@ -0,0 +1,88 @@
+3.1.0 / 2016-01-07
+==================
+ - [minor] Allow multiple stateless components in a single file
+
+3.0.2 / 2016-01-06
+==================
+ - [fix] Ignore URLs in `max-len` (#664)
+
+3.0.1 / 2016-01-06
+==================
+ - [fix] because we use babel, keywords should not be quoted
+
+3.0.0 / 2016-01-04
+==================
+ - [breaking] enable `quote-props` rule (#632)
+ - [breaking] Define a max line length of 100 characters (#639)
+ - [breaking] [react] Minor cleanup for the React styleguide, add `react/jsx-no-bind` (#619)
+ - [breaking] update best-practices config to prevent parameter object manipulation (#627)
+ - [minor] Enable react/no-is-mounted rule (#635, #633)
+ - [minor] Sort react/prefer-es6-class alphabetically (#634)
+ - [minor] enable react/prefer-es6-class rule
+ - Permit strict mode in "legacy" config
+ - [react] add missing rules from eslint-plugin-react (enforcing where necessary) (#581)
+ - [dev deps] update `eslint-plugin-react`
+
+2.1.1 / 2015-12-15
+==================
+ - [fix] Remove deprecated react/jsx-quotes (#622)
+
+2.1.0 / 2015-12-15
+==================
+ - [fix] use `require.resolve` to allow nested `extend`s (#582)
+ - [new] enable `object-shorthand` rule (#621)
+ - [new] enable `arrow-spacing` rule (#517)
+ - [docs] flesh out react rule defaults (#618)
+
+2.0.0 / 2015-12-03
+==================
+ - [breaking] `space-before-function-paren`: require function spacing: `function (` (#605)
+ - [breaking] `indent`: Fix switch statement indentation rule (#606)
+ - [breaking] `array-bracket-spacing`, `computed-property-spacing`: disallow spacing inside brackets (#594)
+ - [breaking] `object-curly-spacing`: require padding inside curly braces (#594)
+ - [breaking] `space-in-parens`: disallow spaces in parens (#594)
+
+1.0.2 / 2015-11-25
+==================
+ - [breaking] `no-multiple-empty-lines`: only allow 1 blank line at EOF (#578)
+ - [new] `restParams`: enable rest params (#592)
+
+1.0.1 / 2015-11-25
+==================
+ - *erroneous publish*
+
+1.0.0 / 2015-11-08
+==================
+ - require `eslint` `v1.0.0` or higher
+ - remove `babel-eslint` dependency
+
+0.1.1 / 2015-11-05
+==================
+ - remove id-length rule (#569)
+ - enable `no-mixed-spaces-and-tabs` (#539)
+ - enable `no-const-assign` (#560)
+ - enable `space-before-keywords` (#554)
+
+0.1.0 / 2015-11-05
+==================
+ - switch to modular rules files courtesy the [eslint-config-default][ecd] project and [@taion][taion]. [PR][pr-modular]
+ - export `eslint-config-airbnb/legacy` for ES5-only users. `eslint-config-airbnb/legacy` does not require the `babel-eslint` parser. [PR][pr-legacy]
+
+0.0.9 / 2015-09-24
+==================
+- add rule `no-undef`
+- add rule `id-length`
+
+0.0.8 / 2015-08-21
+==================
+ - now has a changelog
+ - now is modular (see instructions above for with react and without react versions)
+
+0.0.7 / 2015-07-30
+==================
+ - TODO: fill in
+
+[ecd]: https://github.com/walmartlabs/eslint-config-defaults
+[taion]: https://github.com/taion
+[pr-modular]: https://github.com/airbnb/javascript/pull/526
+[pr-legacy]: https://github.com/airbnb/javascript/pull/527
diff --git a/packages/eslint-config-airbnb/README.md b/packages/eslint-config-airbnb/README.md
index ac184f1adb..26c795f3f8 100644
--- a/packages/eslint-config-airbnb/README.md
+++ b/packages/eslint-config-airbnb/README.md
@@ -1,19 +1,35 @@
# eslint-config-airbnb
+[](http://badge.fury.io/js/eslint-config-airbnb)
+
This package provides Airbnb's .eslintrc as an extensible shared config.
## Usage
-### With React Style
+We export three ESLint configurations for your usage.
+
+### eslint-config-airbnb
+
+Our default export contains all of our ESLint rules, including EcmaScript 6+
+and React. It requires `eslint` and `eslint-plugin-react`.
-1. `npm install --save-dev eslint-config-airbnb babel-eslint eslint-plugin-react`
+1. `npm install --save-dev eslint-config-airbnb eslint-plugin-react eslint`
2. add `"extends": "airbnb"` to your .eslintrc
-### Without React Style
+### eslint-config-airbnb/base
-1. `npm install --save-dev eslint-config-airbnb babel-eslint `
+Lints ES6+ but does not lint React. Requires `eslint`.
+
+1. `npm install --save-dev eslint-config-airbnb eslint`
2. add `"extends": "airbnb/base"` to your .eslintrc
+### eslint-config-airbnb/legacy
+
+Lints ES5 and below. Only requires `eslint`.
+
+1. `npm install --save-dev eslint-config-airbnb eslint`
+2. add `"extends": "airbnb/legacy"` 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.
@@ -27,9 +43,3 @@ 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.js b/packages/eslint-config-airbnb/base.js
new file mode 100644
index 0000000000..093bd541be
--- /dev/null
+++ b/packages/eslint-config-airbnb/base.js
@@ -0,0 +1,7 @@
+module.exports = {
+ 'extends': [
+ 'eslint-config-airbnb/legacy',
+ 'eslint-config-airbnb/rules/es6',
+ ].map(require.resolve),
+ 'rules': {}
+};
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
index 3cda9b0f9c..5a5c535e74 100644
--- a/packages/eslint-config-airbnb/index.js
+++ b/packages/eslint-config-airbnb/index.js
@@ -1,13 +1,8 @@
-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;
+module.exports = {
+ 'extends': [
+ 'eslint-config-airbnb/base',
+ 'eslint-config-airbnb/rules/strict',
+ 'eslint-config-airbnb/rules/react',
+ ].map(require.resolve),
+ rules: {}
+};
diff --git a/packages/eslint-config-airbnb/legacy.js b/packages/eslint-config-airbnb/legacy.js
new file mode 100644
index 0000000000..257b9dd868
--- /dev/null
+++ b/packages/eslint-config-airbnb/legacy.js
@@ -0,0 +1,20 @@
+module.exports = {
+ 'extends': [
+ 'eslint-config-airbnb/rules/best-practices',
+ 'eslint-config-airbnb/rules/errors',
+ 'eslint-config-airbnb/rules/legacy',
+ 'eslint-config-airbnb/rules/node',
+ 'eslint-config-airbnb/rules/style',
+ 'eslint-config-airbnb/rules/variables'
+ ].map(require.resolve),
+ 'env': {
+ 'browser': true,
+ 'node': true,
+ 'amd': false,
+ 'mocha': false,
+ 'jasmine': false
+ },
+ 'ecmaFeatures': {},
+ 'globals': {},
+ 'rules': {}
+};
diff --git a/packages/eslint-config-airbnb/package.json b/packages/eslint-config-airbnb/package.json
index 050567251f..016b02098a 100644
--- a/packages/eslint-config-airbnb/package.json
+++ b/packages/eslint-config-airbnb/package.json
@@ -1,11 +1,11 @@
{
"name": "eslint-config-airbnb",
- "version": "0.0.8",
+ "version": "3.1.0",
"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"
+ "lint": "eslint .",
+ "test": "babel-tape-runner ./test/test-*.js"
},
"repository": {
"type": "git",
@@ -20,17 +20,30 @@
"styleguide"
],
"author": "Jake Teton-Landis (https://twitter.com/@jitl)",
+ "contributors": [
+ {
+ "name": "Jake Teton-Landis",
+ "url": "https://twitter.com/jitl"
+ },
+ {
+ "name": "Jordan Harband",
+ "email": "ljharb@gmail.com",
+ "url": "http://ljharb.codes/"
+ }
+ ],
"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"
+ "eslint": "^1.10.3",
+ "eslint-plugin-react": "^3.12.0",
+ "react": "^0.13.3",
+ "tape": "^4.2.2"
+ },
+ "peerDependencies": {
+ "eslint": ">=1.0.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/rules/best-practices.js b/packages/eslint-config-airbnb/rules/best-practices.js
new file mode 100644
index 0000000000..82e5f9e289
--- /dev/null
+++ b/packages/eslint-config-airbnb/rules/best-practices.js
@@ -0,0 +1,115 @@
+module.exports = {
+ 'rules': {
+ // Enforces getter/setter pairs in objects
+ 'accessor-pairs': 0,
+ // treat var statements as if they were block scoped
+ 'block-scoped-var': 2,
+ // specify the maximum cyclomatic complexity allowed in a program
+ 'complexity': [0, 11],
+ // require return statements to either always or never specify values
+ 'consistent-return': 2,
+ // specify curly brace conventions for all control statements
+ 'curly': [2, 'multi-line'],
+ // require default case in switch statements
+ 'default-case': 2,
+ // encourages use of dot notation whenever possible
+ 'dot-notation': [2, { 'allowKeywords': true}],
+ // enforces consistent newlines before or after dots
+ 'dot-location': 0,
+ // require the use of === and !==
+ 'eqeqeq': 2,
+ // make sure for-in loops have an if statement
+ 'guard-for-in': 2,
+ // disallow the use of alert, confirm, and prompt
+ 'no-alert': 1,
+ // disallow use of arguments.caller or arguments.callee
+ 'no-caller': 2,
+ // disallow division operators explicitly at beginning of regular expression
+ 'no-div-regex': 0,
+ // disallow else after a return in an if
+ 'no-else-return': 2,
+ // disallow use of labels for anything other then loops and switches
+ 'no-empty-label': 2,
+ // disallow comparisons to null without a type-checking operator
+ 'no-eq-null': 0,
+ // disallow use of eval()
+ 'no-eval': 2,
+ // disallow adding to native types
+ 'no-extend-native': 2,
+ // disallow unnecessary function binding
+ 'no-extra-bind': 2,
+ // disallow fallthrough of case statements
+ 'no-fallthrough': 2,
+ // disallow the use of leading or trailing decimal points in numeric literals
+ 'no-floating-decimal': 2,
+ // disallow the type conversions with shorter notations
+ 'no-implicit-coercion': 0,
+ // disallow use of eval()-like methods
+ 'no-implied-eval': 2,
+ // disallow this keywords outside of classes or class-like objects
+ 'no-invalid-this': 0,
+ // disallow usage of __iterator__ property
+ 'no-iterator': 2,
+ // disallow use of labeled statements
+ 'no-labels': 2,
+ // disallow unnecessary nested blocks
+ 'no-lone-blocks': 2,
+ // disallow creation of functions within loops
+ 'no-loop-func': 2,
+ // disallow use of multiple spaces
+ 'no-multi-spaces': 2,
+ // disallow use of multiline strings
+ 'no-multi-str': 2,
+ // disallow reassignments of native objects
+ 'no-native-reassign': 2,
+ // disallow use of new operator when not part of the assignment or comparison
+ 'no-new': 2,
+ // disallow use of new operator for Function object
+ 'no-new-func': 2,
+ // disallows creating new instances of String,Number, and Boolean
+ 'no-new-wrappers': 2,
+ // disallow use of (old style) octal literals
+ 'no-octal': 2,
+ // disallow use of octal escape sequences in string literals, such as
+ // var foo = 'Copyright \251';
+ 'no-octal-escape': 2,
+ // disallow reassignment of function parameters
+ // disallow parameter object manipulation
+ // rule: http://eslint.org/docs/rules/no-param-reassign.html
+ 'no-param-reassign': [2, { 'props': true }],
+ // disallow use of process.env
+ 'no-process-env': 0,
+ // disallow usage of __proto__ property
+ 'no-proto': 2,
+ // disallow declaring the same variable more then once
+ 'no-redeclare': 2,
+ // disallow use of assignment in return statement
+ 'no-return-assign': 2,
+ // disallow use of `javascript:` urls.
+ 'no-script-url': 2,
+ // disallow comparisons where both sides are exactly the same
+ 'no-self-compare': 2,
+ // disallow use of comma operator
+ 'no-sequences': 2,
+ // restrict what can be thrown as an exception
+ 'no-throw-literal': 2,
+ // disallow usage of expressions in statement position
+ 'no-unused-expressions': 2,
+ // disallow unnecessary .call() and .apply()
+ 'no-useless-call': 0,
+ // disallow use of void operator
+ 'no-void': 0,
+ // disallow usage of configurable warning terms in comments: e.g. todo
+ 'no-warning-comments': [0, { 'terms': ['todo', 'fixme', 'xxx'], 'location': 'start' }],
+ // disallow use of the with statement
+ 'no-with': 2,
+ // require use of the second argument for parseInt()
+ 'radix': 2,
+ // requires to declare all vars on top of their containing scope
+ 'vars-on-top': 2,
+ // require immediate function invocation to be wrapped in parentheses
+ 'wrap-iife': [2, 'any'],
+ // require or disallow Yoda conditions
+ 'yoda': 2
+ }
+};
diff --git a/packages/eslint-config-airbnb/rules/errors.js b/packages/eslint-config-airbnb/rules/errors.js
new file mode 100644
index 0000000000..ec1b1aab0e
--- /dev/null
+++ b/packages/eslint-config-airbnb/rules/errors.js
@@ -0,0 +1,60 @@
+module.exports = {
+ 'rules': {
+ // disallow trailing commas in object literals
+ 'comma-dangle': [2, 'always-multiline'],
+ // disallow assignment in conditional expressions
+ 'no-cond-assign': [2, 'always'],
+ // disallow use of console
+ 'no-console': 1,
+ // disallow use of constant expressions in conditions
+ 'no-constant-condition': 1,
+ // disallow control characters in regular expressions
+ 'no-control-regex': 2,
+ // disallow use of debugger
+ 'no-debugger': 1,
+ // disallow duplicate arguments in functions
+ 'no-dupe-args': 2,
+ // disallow duplicate keys when creating object literals
+ 'no-dupe-keys': 2,
+ // disallow a duplicate case label.
+ 'no-duplicate-case': 2,
+ // disallow the use of empty character classes in regular expressions
+ 'no-empty-character-class': 2,
+ // disallow empty statements
+ 'no-empty': 2,
+ // disallow assigning to the exception in a catch block
+ 'no-ex-assign': 2,
+ // disallow double-negation boolean casts in a boolean context
+ 'no-extra-boolean-cast': 0,
+ // disallow unnecessary parentheses
+ 'no-extra-parens': [2, 'functions'],
+ // disallow unnecessary semicolons
+ 'no-extra-semi': 2,
+ // disallow overwriting functions written as function declarations
+ 'no-func-assign': 2,
+ // disallow function or variable declarations in nested blocks
+ 'no-inner-declarations': 2,
+ // disallow invalid regular expression strings in the RegExp constructor
+ 'no-invalid-regexp': 2,
+ // disallow irregular whitespace outside of strings and comments
+ 'no-irregular-whitespace': 2,
+ // disallow negation of the left operand of an in expression
+ 'no-negated-in-lhs': 2,
+ // disallow the use of object properties of the global object (Math and JSON) as functions
+ 'no-obj-calls': 2,
+ // disallow multiple spaces in a regular expression literal
+ 'no-regex-spaces': 2,
+ // disallow sparse arrays
+ 'no-sparse-arrays': 2,
+ // disallow unreachable statements after a return, throw, continue, or break statement
+ 'no-unreachable': 2,
+ // disallow comparisons with the value NaN
+ 'use-isnan': 2,
+ // ensure JSDoc comments are valid
+ 'valid-jsdoc': 0,
+ // ensure that the results of typeof are compared against a valid string
+ 'valid-typeof': 2,
+ // Avoid code that looks like two expressions but is actually one
+ 'no-unexpected-multiline': 0
+ }
+};
diff --git a/packages/eslint-config-airbnb/rules/es6.js b/packages/eslint-config-airbnb/rules/es6.js
new file mode 100644
index 0000000000..3c277064b6
--- /dev/null
+++ b/packages/eslint-config-airbnb/rules/es6.js
@@ -0,0 +1,54 @@
+module.exports = {
+ 'env': {
+ 'es6': false
+ },
+ '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,
+ 'restParams': true,
+ 'spread': true,
+ 'superInFunctions': true,
+ 'templateStrings': true,
+ 'jsx': true
+ },
+ 'rules': {
+ // require parens in arrow function arguments
+ 'arrow-parens': 0,
+ // require space before/after arrow function's arrow
+ // https://github.com/eslint/eslint/blob/master/docs/rules/arrow-spacing.md
+ 'arrow-spacing': [2, { 'before': true, 'after': true }],
+ // verify super() callings in constructors
+ 'constructor-super': 0,
+ // enforce the spacing around the * in generator functions
+ 'generator-star-spacing': 0,
+ // disallow modifying variables of class declarations
+ 'no-class-assign': 0,
+ // disallow modifying variables that are declared using const
+ 'no-const-assign': 2,
+ // disallow to use this/super before super() calling in constructors.
+ 'no-this-before-super': 0,
+ // require let or const instead of var
+ 'no-var': 2,
+ // require method and property shorthand syntax for object literals
+ // https://github.com/eslint/eslint/blob/master/docs/rules/object-shorthand.md
+ 'object-shorthand': [2, 'always'],
+ // suggest using of const declaration for variables that are never modified after declared
+ 'prefer-const': 2,
+ // suggest using the spread operator instead of .apply()
+ 'prefer-spread': 0,
+ // suggest using Reflect methods where applicable
+ 'prefer-reflect': 0,
+ // disallow generator functions that do not have yield
+ 'require-yield': 0
+ }
+};
diff --git a/packages/eslint-config-airbnb/rules/legacy.js b/packages/eslint-config-airbnb/rules/legacy.js
new file mode 100644
index 0000000000..e94c774f26
--- /dev/null
+++ b/packages/eslint-config-airbnb/rules/legacy.js
@@ -0,0 +1,14 @@
+module.exports = {
+ 'rules': {
+ // specify the maximum depth that blocks can be nested
+ 'max-depth': [0, 4],
+ // limits the number of parameters that can be used in the function declaration.
+ 'max-params': [0, 3],
+ // specify the maximum number of statement allowed in a function
+ 'max-statements': [0, 10],
+ // disallow use of bitwise operators
+ 'no-bitwise': 0,
+ // disallow use of unary operators, ++ and --
+ 'no-plusplus': 0
+ }
+};
diff --git a/packages/eslint-config-airbnb/rules/node.js b/packages/eslint-config-airbnb/rules/node.js
new file mode 100644
index 0000000000..16b6f20d45
--- /dev/null
+++ b/packages/eslint-config-airbnb/rules/node.js
@@ -0,0 +1,23 @@
+module.exports = {
+ 'env': {
+ 'node': true
+ },
+ 'rules': {
+ // enforce return after a callback
+ 'callback-return': 0,
+ // enforces error handling in callbacks (node environment)
+ 'handle-callback-err': 0,
+ // disallow mixing regular variable and require declarations
+ 'no-mixed-requires': [0, false],
+ // disallow use of new operator with the require function
+ 'no-new-require': 0,
+ // disallow string concatenation with __dirname and __filename
+ 'no-path-concat': 0,
+ // disallow process.exit()
+ 'no-process-exit': 0,
+ // restrict usage of specified node modules
+ 'no-restricted-modules': 0,
+ // disallow use of synchronous methods (off by default)
+ 'no-sync': 0
+ }
+};
diff --git a/packages/eslint-config-airbnb/rules/react.js b/packages/eslint-config-airbnb/rules/react.js
new file mode 100644
index 0000000000..c17328ebe8
--- /dev/null
+++ b/packages/eslint-config-airbnb/rules/react.js
@@ -0,0 +1,139 @@
+module.exports = {
+ 'plugins': [
+ 'react'
+ ],
+ 'ecmaFeatures': {
+ 'jsx': true
+ },
+ // View link below for react rules documentation
+ // https://github.com/yannickcr/eslint-plugin-react#list-of-supported-rules
+ 'rules': {
+ // Prevent missing displayName in a React component definition
+ // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/display-name.md
+ 'react/display-name': [0, {'acceptTranspilerName': false}],
+ // Forbid certain propTypes (any, array, object)
+ // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/forbid-prop-types.md
+ 'react/forbid-prop-types': [0, {'forbid': ['any', 'array', 'object']}],
+ // Enforce boolean attributes notation in JSX
+ // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-boolean-value.md
+ 'react/jsx-boolean-value': [2, 'never'],
+ // Validate closing bracket location in JSX
+ // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-closing-bracket-location.md
+ 'react/jsx-closing-bracket-location': [2, 'line-aligned'],
+ // Enforce or disallow spaces inside of curly braces in JSX attributes
+ // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-curly-spacing.md
+ 'react/jsx-curly-spacing': [0, 'never', {'allowMultiline': true}],
+ // Enforce event handler naming conventions in JSX
+ // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-handler-names.md
+ 'react/jsx-handler-names': [0, {
+ 'eventHandlerPrefix': 'handle',
+ 'eventHandlerPropPrefix': 'on',
+ }],
+ // Validate props indentation in JSX
+ // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-indent-props.md
+ 'react/jsx-indent-props': [2, 2],
+ // Validate JSX has key prop when in array or iterator
+ // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-key.md
+ 'react/jsx-key': 0,
+ // Limit maximum of props on a single line in JSX
+ // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-max-props-per-line.md
+ 'react/jsx-max-props-per-line': [0, {'maximum': 1}],
+ // Prevent usage of .bind() and arrow functions in JSX props
+ // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-bind.md
+ 'react/jsx-no-bind': 2,
+ // Prevent duplicate props in JSX
+ // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-duplicate-props.md
+ 'react/jsx-no-duplicate-props': [0, {'ignoreCase': false}],
+ // Prevent usage of unwrapped JSX strings
+ // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-literals.md
+ 'react/jsx-no-literals': 0,
+ // Disallow undeclared variables in JSX
+ // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-undef.md
+ 'react/jsx-no-undef': 2,
+ // Enforce PascalCase for user-defined JSX components
+ // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-pascal-case.md
+ 'react/jsx-pascal-case': 0,
+ // Enforce propTypes declarations alphabetical sorting
+ // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-sort-prop-types.md
+ 'react/jsx-sort-prop-types': [0, {
+ 'ignoreCase': false,
+ 'callbacksLast': false,
+ }],
+ // Enforce props alphabetical sorting
+ // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-sort-props.md
+ 'react/jsx-sort-props': [0, {
+ 'ignoreCase': false,
+ 'callbacksLast': false,
+ }],
+ // Prevent React to be incorrectly marked as unused
+ // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-uses-react.md
+ 'react/jsx-uses-react': [2, {'pragma': 'React'}],
+ // Prevent variables used in JSX to be incorrectly marked as unused
+ // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-uses-vars.md
+ 'react/jsx-uses-vars': 2,
+ // Prevent usage of dangerous JSX properties
+ // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-danger.md
+ 'react/no-danger': 0,
+ // Prevent usage of deprecated methods
+ // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-deprecated.md
+ 'react/no-deprecated': [1, {"react": "0.14.0"}],
+ // Prevent usage of setState in componentDidMount
+ // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-did-mount-set-state.md
+ 'react/no-did-mount-set-state': [2, 'allow-in-func'],
+ // Prevent usage of setState in componentDidUpdate
+ // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-did-update-set-state.md
+ 'react/no-did-update-set-state': [2, 'allow-in-func'],
+ // Prevent direct mutation of this.state
+ // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-direct-mutation-state.md
+ 'react/no-direct-mutation-state': 0,
+ // Prevent usage of isMounted
+ // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-is-mounted.md
+ 'react/no-is-mounted': 2,
+ // Prevent multiple component definition per file
+ // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-multi-comp.md
+ 'react/no-multi-comp': [2, {'ignoreStateless': true}],
+ // Prevent usage of setState
+ // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-set-state.md
+ 'react/no-set-state': 0,
+ // Prevent using string references
+ // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-string-refs.md
+ 'react/no-string-refs': 0,
+ // Prevent usage of unknown DOM property
+ // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-unknown-property.md
+ 'react/no-unknown-property': 2,
+ // Require ES6 class declarations over React.createClass
+ // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/prefer-es6-class.md
+ 'react/prefer-es6-class': [2, 'always'],
+ // Prevent missing props validation in a React component definition
+ // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/prop-types.md
+ 'react/prop-types': [2, {'ignore': [], customValidators: []}],
+ // Prevent missing React when using JSX
+ // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/react-in-jsx-scope.md
+ 'react/react-in-jsx-scope': 2,
+ // Restrict file extensions that may be required
+ // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/require-extension.md
+ 'react/require-extension': [0, {'extensions': ['.jsx']}],
+ // Prevent extra closing tags for components without children
+ // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/self-closing-comp.md
+ 'react/self-closing-comp': 2,
+ // Enforce component methods order
+ // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/sort-comp.md
+ 'react/sort-comp': [2, {
+ 'order': [
+ 'lifecycle',
+ '/^on.+$/',
+ '/^(get|set)(?!(InitialState$|DefaultProps$|ChildContext$)).+$/',
+ 'everything-else',
+ '/^render.+$/',
+ 'render'
+ ]
+ }],
+ // Prevent missing parentheses around multilines JSX
+ // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/wrap-multilines.md
+ 'react/wrap-multilines': [2, {
+ declaration: true,
+ assignment: true,
+ return: true
+ }],
+ }
+};
diff --git a/packages/eslint-config-airbnb/rules/strict.js b/packages/eslint-config-airbnb/rules/strict.js
new file mode 100644
index 0000000000..6d32f8ca59
--- /dev/null
+++ b/packages/eslint-config-airbnb/rules/strict.js
@@ -0,0 +1,6 @@
+module.exports = {
+ 'rules': {
+ // babel inserts `'use strict';` for us
+ 'strict': [2, 'never']
+ }
+};
diff --git a/packages/eslint-config-airbnb/rules/style.js b/packages/eslint-config-airbnb/rules/style.js
new file mode 100644
index 0000000000..ec68b16e5d
--- /dev/null
+++ b/packages/eslint-config-airbnb/rules/style.js
@@ -0,0 +1,125 @@
+module.exports = {
+ 'rules': {
+ // enforce spacing inside array brackets
+ 'array-bracket-spacing': [2, 'never'],
+ // enforce one true brace style
+ 'brace-style': [2, '1tbs', {'allowSingleLine': true }],
+ // require camel case names
+ 'camelcase': [2, {'properties': 'never'}],
+ // enforce spacing before and after comma
+ 'comma-spacing': [2, {'before': false, 'after': true}],
+ // enforce one true comma style
+ 'comma-style': [2, 'last'],
+ // disallow padding inside computed properties
+ 'computed-property-spacing': [2, 'never'],
+ // enforces consistent naming when capturing the current execution context
+ 'consistent-this': 0,
+ // enforce newline at the end of file, with no multiple empty lines
+ 'eol-last': 2,
+ // require function expressions to have a name
+ 'func-names': 1,
+ // enforces use of function declarations or expressions
+ 'func-style': 0,
+ // this option enforces minimum and maximum identifier lengths (variable names, property names etc.)
+ 'id-length': 0,
+ // this option sets a specific tab width for your code
+ // https://github.com/eslint/eslint/blob/master/docs/rules/indent.md
+ 'indent': [2, 2, { "SwitchCase": 1, "VariableDeclarator": 1 }],
+ // specify whether double or single quotes should be used in JSX attributes
+ // http://eslint.org/docs/rules/jsx-quotes
+ 'jsx-quotes': [2, 'prefer-double'],
+ // enforces spacing between keys and values in object literal properties
+ 'key-spacing': [2, {'beforeColon': false, 'afterColon': true}],
+ // enforces empty lines around comments
+ 'lines-around-comment': 0,
+ // disallow mixed 'LF' and 'CRLF' as linebreaks
+ 'linebreak-style': 0,
+ // specify the maximum length of a line in your program
+ // https://github.com/eslint/eslint/blob/master/docs/rules/max-len.md
+ 'max-len': [2, 100, 2, {
+ 'ignoreUrls': true,
+ 'ignoreComments': false
+ }],
+ // specify the maximum depth callbacks can be nested
+ 'max-nested-callbacks': 0,
+ // require a capital letter for constructors
+ 'new-cap': [2, {'newIsCap': true}],
+ // disallow the omission of parentheses when invoking a constructor with no arguments
+ 'new-parens': 0,
+ // allow/disallow an empty newline after var statement
+ 'newline-after-var': 0,
+ // disallow use of the Array constructor
+ 'no-array-constructor': 0,
+ // disallow use of the continue statement
+ 'no-continue': 0,
+ // disallow comments inline after code
+ 'no-inline-comments': 0,
+ // disallow if as the only statement in an else block
+ 'no-lonely-if': 0,
+ // disallow mixed spaces and tabs for indentation
+ 'no-mixed-spaces-and-tabs': 2,
+ // disallow multiple empty lines and only one newline at the end
+ 'no-multiple-empty-lines': [2, {'max': 2, 'maxEOF': 1}],
+ // disallow nested ternary expressions
+ 'no-nested-ternary': 2,
+ // disallow use of the Object constructor
+ 'no-new-object': 2,
+ // disallow space between function identifier and application
+ 'no-spaced-func': 2,
+ // disallow the use of ternary operators
+ 'no-ternary': 0,
+ // disallow trailing whitespace at the end of lines
+ 'no-trailing-spaces': 2,
+ // disallow dangling underscores in identifiers
+ 'no-underscore-dangle': 0,
+ // disallow the use of Boolean literals in conditional expressions
+ 'no-unneeded-ternary': 0,
+ // require padding inside curly braces
+ 'object-curly-spacing': [2, 'always'],
+ // allow just one var statement per function
+ 'one-var': [2, 'never'],
+ // require assignment operator shorthand where possible or prohibit it entirely
+ 'operator-assignment': 0,
+ // enforce operators to be placed before or after line breaks
+ 'operator-linebreak': 0,
+ // enforce padding within blocks
+ 'padded-blocks': [2, 'never'],
+ // require quotes around object literal property names
+ // http://eslint.org/docs/rules/quote-props.html
+ 'quote-props': [2, 'as-needed', { 'keywords': false, 'unnecessary': true, 'numbers': false }],
+ // specify whether double or single quotes should be used
+ 'quotes': [2, 'single', 'avoid-escape'],
+ // require identifiers to match the provided regular expression
+ 'id-match': 0,
+ // enforce spacing before and after semicolons
+ 'semi-spacing': [2, {'before': false, 'after': true}],
+ // require or disallow use of semicolons instead of ASI
+ 'semi': [2, 'always'],
+ // sort variables within the same declaration block
+ 'sort-vars': 0,
+ // require a space before certain keywords
+ 'space-before-keywords': [2, 'always'],
+ // require a space after certain keywords
+ 'space-after-keywords': [2, 'always'],
+ // require or disallow space before blocks
+ 'space-before-blocks': 2,
+ // require or disallow space before function opening parenthesis
+ // https://github.com/eslint/eslint/blob/master/docs/rules/space-before-function-paren.md
+ 'space-before-function-paren': [2, { 'anonymous': 'always', 'named': 'never' }],
+ // require or disallow spaces inside parentheses
+ 'space-in-parens': [2, 'never'],
+ // require spaces around operators
+ 'space-infix-ops': 2,
+ // require a space after return, throw, and case
+ 'space-return-throw-case': 2,
+ // Require or disallow spaces before/after unary operators
+ 'space-unary-ops': 0,
+ // require or disallow a space immediately following the // or /* in a comment
+ 'spaced-comment': [2, 'always', {
+ 'exceptions': ['-', '+'],
+ 'markers': ['=', '!'] // space here to support sprockets directives
+ }],
+ // require regex literals to be wrapped in parentheses
+ 'wrap-regex': 0
+ }
+};
diff --git a/packages/eslint-config-airbnb/rules/variables.js b/packages/eslint-config-airbnb/rules/variables.js
new file mode 100644
index 0000000000..3da93fe826
--- /dev/null
+++ b/packages/eslint-config-airbnb/rules/variables.js
@@ -0,0 +1,26 @@
+module.exports = {
+ 'rules': {
+ // enforce or disallow variable initializations at definition
+ 'init-declarations': 0,
+ // disallow the catch clause parameter name being the same as a variable in the outer scope
+ 'no-catch-shadow': 0,
+ // disallow deletion of variables
+ 'no-delete-var': 2,
+ // disallow labels that share a name with a variable
+ 'no-label-var': 0,
+ // disallow shadowing of names such as arguments
+ 'no-shadow-restricted-names': 2,
+ // disallow declaration of variables already declared in the outer scope
+ 'no-shadow': 2,
+ // disallow use of undefined when initializing variables
+ 'no-undef-init': 0,
+ // disallow use of undeclared variables unless mentioned in a /*global */ block
+ 'no-undef': 2,
+ // disallow use of undefined variable
+ 'no-undefined': 0,
+ // disallow declaration of variables that are not used in the code
+ 'no-unused-vars': [2, {'vars': 'local', 'args': 'after-used'}],
+ // disallow use of variables before they are defined
+ 'no-use-before-define': 2
+ }
+};
diff --git a/packages/eslint-config-airbnb/test/.eslintrc b/packages/eslint-config-airbnb/test/.eslintrc
new file mode 100644
index 0000000000..7f79874e41
--- /dev/null
+++ b/packages/eslint-config-airbnb/test/.eslintrc
@@ -0,0 +1,9 @@
+{
+ "rules": {
+ // disabled because I find it tedious to write tests while following this
+ // rule
+ "no-shadow": 0,
+ // tests uses `t` for tape
+ "id-length": [2, {"min": 2, "properties": "never", "exceptions": ["t"]}]
+ }
+}
diff --git a/packages/eslint-config-airbnb/test/test-base.js b/packages/eslint-config-airbnb/test/test-base.js
index ecf06cdf58..24aa884cd0 100644
--- a/packages/eslint-config-airbnb/test/test-base.js
+++ b/packages/eslint-config-airbnb/test/test-base.js
@@ -1,13 +1,30 @@
+import fs from 'fs';
+import path from 'path';
import test from 'tape';
-import base from '../base';
-test('base: does not reference react', t => {
- t.plan(2);
+const files = {
+ base: require('../base')
+};
- t.notOk(base.plugins, 'plugins is unspecified');
+fs.readdirSync(path.join(__dirname, '../rules')).forEach(name => {
+ if (name === 'react.js') {
+ return;
+ }
- // 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');
+ files[name] = require(`../rules/${name}`);
+});
+
+Object.keys(files).forEach(name => {
+ const config = files[name];
+
+ test(`${name}: does not reference react`, t => {
+ t.plan(2);
+
+ t.notOk(config.plugins, 'plugins is unspecified');
+
+ // scan rules for react/ and fail if any exist
+ const reactRuleIds = Object.keys(config.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
index 9ef23f6737..1a84b59230 100644
--- a/packages/eslint-config-airbnb/test/test-react-order.js
+++ b/packages/eslint-config-airbnb/test/test-react-order.js
@@ -1,10 +1,15 @@
import test from 'tape';
import { CLIEngine } from 'eslint';
import eslintrc from '../';
+import baseConfig from '../base';
+import reactRules from '../rules/react';
const cli = new CLIEngine({
useEslintrc: false,
baseConfig: eslintrc,
+
+ // This rule fails when executing on text.
+ rules: {indent: 0},
});
function lint(text) {
@@ -24,21 +29,20 @@ ${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.plan(1);
+ t.equal(reactRules.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() { }
+ componentWillMount() {}
+ componentDidMount() {}
+ setFoo() {}
+ getFoo() {}
+ setBar() {}
+ someMethod() {}
+ renderDogs() {}
render() { return ; }
`));
@@ -50,13 +54,13 @@ test('validate react prop order', t => {
t.test('order: when random method is first', t => {
t.plan(2);
const result = lint(wrapComponent(`
- someMethod() { }
- componentWillMount() { }
- componentDidMount() { }
- setFoo() { }
- getFoo() { }
- setBar() { }
- renderDogs() { }
+ someMethod() {}
+ componentWillMount() {}
+ componentDidMount() {}
+ setFoo() {}
+ getFoo() {}
+ setBar() {}
+ renderDogs() {}
render() { return ; }
`));
@@ -67,13 +71,13 @@ test('validate react prop order', t => {
t.test('order: when random method after lifecycle methods', t => {
t.plan(2);
const result = lint(wrapComponent(`
- componentWillMount() { }
- componentDidMount() { }
- someMethod() { }
- setFoo() { }
- getFoo() { }
- setBar() { }
- renderDogs() { }
+ componentWillMount() {}
+ componentDidMount() {}
+ someMethod() {}
+ setFoo() {}
+ getFoo() {}
+ setBar() {}
+ renderDogs() {}
render() { return ; }
`));
diff --git a/react/README.md b/react/README.md
index d1ce8c73da..ba23784e1a 100644
--- a/react/README.md
+++ b/react/README.md
@@ -5,6 +5,7 @@
## Table of Contents
1. [Basic Rules](#basic-rules)
+ 1. [Class vs `React.createClass`](#class-vs-reactcreateclass)
1. [Naming](#naming)
1. [Declaration](#declaration)
1. [Alignment](#alignment)
@@ -15,44 +16,51 @@
1. [Tags](#tags)
1. [Methods](#methods)
1. [Ordering](#ordering)
+ 1. [`isMounted`](#ismounted)
## Basic Rules
- Only include one React component per file.
+ - However, multiple [Stateless, or Pure, Components](https://facebook.github.io/react/docs/reusable-components.html#stateless-functions) are allowed per file. eslint rule: [`react/no-multi-comp`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-multi-comp.md#ignorestateless).
- Always use JSX syntax.
- Do not use `React.createElement` unless you're initializing the app from a file that is not JSX.
-## Class vs React.createClass
+## Class vs `React.createClass`
- - Use class extends React.Component unless you have a very good reason to use mixins.
+ - Use `class extends React.Component` unless you have a very good reason to use mixins.
- ```javascript
- // bad
- const Listing = React.createClass({
- render() {
- return ;
- }
- });
-
- // good
- class Listing extends React.Component {
- render() {
- return ;
+ eslint rules: [`react/prefer-es6-class`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/prefer-es6-class.md).
+
+ ```javascript
+ // bad
+ const Listing = React.createClass({
+ render() {
+ return ;
+ }
+ });
+
+ // good
+ class Listing extends React.Component {
+ render() {
+ return ;
+ }
}
- }
- ```
+ ```
## Naming
- **Extensions**: Use `.jsx` extension for React components.
- **Filename**: Use PascalCase for filenames. E.g., `ReservationCard.jsx`.
- - **Reference Naming**: Use PascalCase for React components and camelCase for their instances:
+ - **Reference Naming**: Use PascalCase for React components and camelCase for their instances.
+
+ eslint rules: [`react/jsx-pascal-case`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-pascal-case.md).
+
```javascript
// bad
- const reservationCard = require('./ReservationCard');
+ import reservationCard from './ReservationCard';
// good
- const ReservationCard = require('./ReservationCard');
+ import ReservationCard from './ReservationCard';
// bad
const ReservationItem = ;
@@ -61,21 +69,22 @@
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, `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:
+
```javascript
// bad
- const Footer = require('./Footer/Footer.jsx')
+ import Footer from './Footer/Footer';
// bad
- const Footer = require('./Footer/index.jsx')
+ import Footer from './Footer/index';
// good
- const Footer = require('./Footer')
+ import Footer from './Footer';
```
-
## Declaration
- - Do not use displayName for naming components. Instead, name the component by reference.
+
+ - Do not use `displayName` for naming components. Instead, name the component by reference.
```javascript
// bad
@@ -90,8 +99,11 @@
```
## Alignment
+
- Follow these alignment styles for JSX syntax
+ eslint rules: [`react/jsx-closing-bracket-location`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-closing-bracket-location.md).
+
```javascript
// bad
Why? JSX attributes [can't contain escaped quotes](http://eslint.org/docs/rules/jsx-quotes), so double quotes make conjunctions like `"don't"` easier to type.
+ > Regular HTML attributes also typically use double quotes instead of single, so JSX attributes mirror this convention.
+
+ eslint rules: [`jsx-quotes`](http://eslint.org/docs/rules/jsx-quotes).
+
```javascript
// bad
@@ -132,7 +151,9 @@
```
## Spacing
+
- Always include a single space in your self-closing tag.
+
```javascript
// bad
@@ -149,7 +170,9 @@
```
## Props
+
- Always use camelCase for prop names.
+
```javascript
// bad
```
+ - Omit the value of the prop when it is explicitly `true`.
+
+ eslint rules: [`react/jsx-boolean-value`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-boolean-value.md).
+
+ ```javascript
+ // bad
+
+
+ // good
+
+ ```
+
## Parentheses
- - Wrap JSX tags in parentheses when they span more than one line:
+
+ - Wrap JSX tags in parentheses when they span more than one line.
+
+ eslint rules: [`react/wrap-multilines`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/wrap-multilines.md).
+
```javascript
- /// bad
+ // bad
render() {
return
@@ -191,7 +234,11 @@
```
## Tags
+
- Always self-close tags that have no children.
+
+ eslint rules: [`react/self-closing-comp`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/self-closing-comp.md).
+
```javascript
// bad
@@ -201,6 +248,9 @@
```
- If your component has multi-line properties, close its tag on a new line.
+
+ eslint rules: [`react/jsx-closing-bracket-location`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-closing-bracket-location.md).
+
```javascript
// bad
Why? A bind call in a the render path creates a brand new function on every single render.
+
+ eslint rules: [`react/jsx-no-bind`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-bind.md).
+
+ ```javascript
+ // bad
+ class extends React.Component {
+ onClickDiv() {
+ // do stuff
+ }
+
+ render() {
+ return
+ }
+ }
+
+ // good
+ class extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.onClickDiv = this.onClickDiv.bind(this);
+ }
+
+ onClickDiv() {
+ // do stuff
+ }
+
+ render() {
+ return
+ }
+ }
+ ```
+
- Do not use underscore prefix for internal methods of a React component.
+
```javascript
// bad
React.createClass({
_onClickSubmit() {
// do stuff
- }
+ },
// other stuff
});
@@ -233,79 +321,93 @@
}
// other stuff
- });
+ }
```
## Ordering
- - Ordering for class extends React.Component:
-
- 1. constructor
- 1. optional static methods
- 1. getChildContext
- 1. componentWillMount
- 1. componentDidMount
- 1. componentWillReceiveProps
- 1. shouldComponentUpdate
- 1. componentWillUpdate
- 1. componentDidUpdate
- 1. componentWillUnmount
- 1. *clickHandlers or eventHandlers* like onClickSubmit() or onChangeDescription()
- 1. *getter methods for render* like getSelectReason() or getFooterContent()
- 1. *Optional render methods* like renderNavigation() or renderProfilePicture()
- 1. render
-
- - How to define propTypes, defaultProps, contextTypes, etc...
-
- ```javascript
- import React, { Component, PropTypes } from 'react';
-
- const propTypes = {
- id: PropTypes.number.isRequired,
- url: PropTypes.string.isRequired,
- text: PropTypes.string,
- };
-
- const defaultProps = {
- text: 'Hello World',
- };
-
- export default class Link extends Component {
- static methodsAreOk() {
- return true;
- }
-
- render() {
- return {this.props.text}
+ - Ordering for `class extends React.Component`:
+
+ 1. `constructor`
+ 1. optional `static` methods
+ 1. `getChildContext`
+ 1. `componentWillMount`
+ 1. `componentDidMount`
+ 1. `componentWillReceiveProps`
+ 1. `shouldComponentUpdate`
+ 1. `componentWillUpdate`
+ 1. `componentDidUpdate`
+ 1. `componentWillUnmount`
+ 1. *clickHandlers or eventHandlers* like `onClickSubmit()` or `onChangeDescription()`
+ 1. *getter methods for `render`* like `getSelectReason()` or `getFooterContent()`
+ 1. *Optional render methods* like `renderNavigation()` or `renderProfilePicture()`
+ 1. `render`
+
+ - How to define `propTypes`, `defaultProps`, `contextTypes`, etc...
+
+ ```javascript
+ import React, { PropTypes } from 'react';
+
+ const propTypes = {
+ id: PropTypes.number.isRequired,
+ url: PropTypes.string.isRequired,
+ text: PropTypes.string,
+ };
+
+ const defaultProps = {
+ text: 'Hello World',
+ };
+
+ class Link extends React.Component {
+ static methodsAreOk() {
+ return true;
+ }
+
+ render() {
+ return {this.props.text}
+ }
}
- }
-
- Link.propTypes = propTypes;
- Link.defaultProps = defaultProps;
- ```
-
- - Ordering for React.createClass:
-
- 1. displayName
- 1. propTypes
- 1. contextTypes
- 1. childContextTypes
- 1. mixins
- 1. statics
- 1. defaultProps
- 1. getDefaultProps
- 1. getInitialState
- 1. getChildContext
- 1. componentWillMount
- 1. componentDidMount
- 1. componentWillReceiveProps
- 1. shouldComponentUpdate
- 1. componentWillUpdate
- 1. componentDidUpdate
- 1. componentWillUnmount
- 1. *clickHandlers or eventHandlers* like onClickSubmit() or onChangeDescription()
- 1. *getter methods for render* like getSelectReason() or getFooterContent()
- 1. *Optional render methods* like renderNavigation() or renderProfilePicture()
- 1. render
+
+ Link.propTypes = propTypes;
+ Link.defaultProps = defaultProps;
+
+ export default Link;
+ ```
+
+ - Ordering for `React.createClass`:
+
+ 1. `displayName`
+ 1. `propTypes`
+ 1. `contextTypes`
+ 1. `childContextTypes`
+ 1. `mixins`
+ 1. `statics`
+ 1. `defaultProps`
+ 1. `getDefaultProps`
+ 1. `getInitialState`
+ 1. `getChildContext`
+ 1. `componentWillMount`
+ 1. `componentDidMount`
+ 1. `componentWillReceiveProps`
+ 1. `shouldComponentUpdate`
+ 1. `componentWillUpdate`
+ 1. `componentDidUpdate`
+ 1. `componentWillUnmount`
+ 1. *clickHandlers or eventHandlers* like `onClickSubmit()` or `onChangeDescription()`
+ 1. *getter methods for `render`* like `getSelectReason()` or `getFooterContent()`
+ 1. *Optional render methods* like `renderNavigation()` or `renderProfilePicture()`
+ 1. `render`
+
+ eslint rules: [`react/sort-comp`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/sort-comp.md).
+
+## `isMounted`
+
+ - Do not use `isMounted`.
+
+ > Why? [`isMounted` is an anti-pattern][anti-pattern], is not available when using ES6 classes, and is on its way to being officially deprecated.
+
+ [anti-pattern]: https://facebook.github.io/react/blog/2015/12/16/ismounted-antipattern.html
+
+ eslint rules: [`react/no-is-mounted`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-is-mounted.md).
**[⬆ back to top](#table-of-contents)**