diff --git a/README.md b/README.md index 32c966ce98..e10cca35ea 100644 --- a/README.md +++ b/README.md @@ -346,6 +346,54 @@ Other Style Guides const nodes = Array.from(foo); ``` + - [4.5](#4.5) Use return statements in array method callbacks. It's ok to omit the return if the function body consists of a single statement following [8.2](#8.2). eslint: [`array-callback-return`](http://eslint.org/docs/rules/array-callback-return) + + ```javascript + // good + [1, 2, 3].map((x) => { + const y = x + 1; + return x * y; + }); + + // good + [1, 2, 3].map(x => x + 1); + + // bad + const flat = {}; + [[0, 1], [2, 3], [4, 5]].reduce((memo, item, index) => { + const flatten = memo.concat(item); + flat[index] = memo.concat(item); + }); + + // good + const flat = {}; + [[0, 1], [2, 3], [4, 5]].reduce((memo, item, index) => { + const flatten = memo.concat(item); + flat[index] = flatten; + return flatten; + }); + + // bad + inbox.filter((msg) => { + const { subject, author } = msg; + if (subject === 'Mockingbird') { + return author === 'Harper Lee'; + } else { + return false; + } + }); + + // good + inbox.filter((msg) => { + const { subject, author } = msg; + if (subject === 'Mockingbird') { + return author === 'Harper Lee'; + } + + return false; + }); + ``` + **[⬆ back to top](#table-of-contents)** ## Destructuring @@ -447,7 +495,7 @@ Other Style Guides ``` - - [6.4](#6.4) When programmatically building up strings, use template strings instead of concatenation. eslint: [`prefer-template`](http://eslint.org/docs/rules/prefer-template.html) jscs: [`requireTemplateStrings`](http://jscs.info/rule/requireTemplateStrings) + - [6.4](#6.4) When programmatically building up strings, use template strings instead of concatenation. eslint: [`prefer-template`](http://eslint.org/docs/rules/prefer-template.html) [`template-curly-spacing`](http://eslint.org/docs/rules/template-curly-spacing) jscs: [`requireTemplateStrings`](http://jscs.info/rule/requireTemplateStrings) > Why? Template strings give you a readable, concise syntax with proper newlines and string interpolation features. @@ -462,6 +510,11 @@ Other Style Guides return ['How are you, ', name, '?'].join(); } + // bad + function sayHi(name) { + return `How are you, ${ name }?`; + } + // good function sayHi(name) { return `How are you, ${name}?`; @@ -535,7 +588,7 @@ Other Style Guides ``` - - [7.6](#7.6) Never use `arguments`, opt to use rest syntax `...` instead. + - [7.6](#7.6) Never use `arguments`, opt to use rest syntax `...` instead. [`prefer-rest-params`](http://eslint.org/docs/rules/prefer-rest-params) > Why? `...` is explicit about which arguments you want pulled. Plus rest arguments are a real Array and not Array-like like `arguments`. @@ -771,6 +824,19 @@ Other Style Guides }); ``` + - [8.5](#8.5) Avoid confusing arrow function syntax (`=>`) with comparison operators (`<=`, `>=`). eslint: [`no-confusing-arrow`](http://eslint.org/docs/rules/no-confusing-arrow) + + ```js + // bad + const itemHeight = item => item.height > 256 ? item.largeSize : item.smallSize; + + // bad + const itemHeight = (item) => item.height > 256 ? item.largeSize : item.smallSize; + + // good + const itemHeight = item => { return item.height > 256 ? item.largeSize : item.smallSize; } + ``` + **[⬆ back to top](#table-of-contents)** @@ -883,6 +949,34 @@ Other Style Guides } ``` + - [9.5](#9.5) Classes have a default constructor if one is not specified. An empty constructor function or one that just delegates to a parent class is unnecessary. [`no-useless-constructor`](http://eslint.org/docs/rules/no-useless-constructor) + + ```javascript + // bad + class Jedi { + constructor() {} + + getName() { + return this.name; + } + } + + // bad + class Rey extends Jedi { + constructor(...args) { + super(args); + } + } + + // good + class Rey extends Jedi { + constructor(...args) { + super(args); + this.name = 'Rey'; + } + } + ``` + **[⬆ back to top](#table-of-contents)** @@ -1592,8 +1686,8 @@ Other Style Guides })(this);↵ ``` - - [18.6](#18.6) Use indentation when making long method chains. Use a leading dot, which - emphasizes that the line is a method call, not a new statement. + - [18.6](#18.6) Use indentation when making long method chains (more than 2 method chains). Use a leading dot, which + emphasizes that the line is a method call, not a new statement. eslint: [`newline-per-chained-call`](http://eslint.org/docs/rules/newline-per-chained-call) [`no-whitespace-before-property`](http://eslint.org/docs/rules/no-whitespace-before-property) ```javascript // bad @@ -1630,6 +1724,9 @@ Other Style Guides .append('svg:g') .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')') .call(tron.led); + + // good + const leds = stage.selectAll('.led').data(data); ``` - [18.7](#18.7) Leave a blank line after blocks and before the next statement. jscs: [`requirePaddingNewLinesAfterBlocks`](http://jscs.info/rule/requirePaddingNewLinesAfterBlocks) diff --git a/packages/eslint-config-airbnb/CHANGELOG.md b/packages/eslint-config-airbnb/CHANGELOG.md index 7c47c680f5..fcb16ec26c 100644 --- a/packages/eslint-config-airbnb/CHANGELOG.md +++ b/packages/eslint-config-airbnb/CHANGELOG.md @@ -1,3 +1,21 @@ +6.0.0 / 2016-02-21 +================== +- [breaking] enable `array-callback-return` +- [breaking] enable `no-confusing-arrow` +- [breaking] enable `no-new-symbol` +- [breaking] enable `no-restricted-imports` +- [breaking] enable `no-useless-constructor` +- [breaking] enable `prefer-rest-params` +- [breaking] enable `template-curly-spaces` +- [breaking] enable `newline-per-chained-call` +- [breaking] enable `one-var-declaration-per-line` +- [breaking] enable `no-self-assign` +- [breaking] enable `no-whitespace-before-property` +- [breaking] [react] enable `react/jsx-space-before-closing` +- [breaking] [react] enable `static-methods` at top of `react/sort-comp` +- [breaking] [react] don't `ignoreTranspilerName` for `react/display-name` +- [peer+dev deps] update `eslint`, `eslint-plugin-react` + 5.0.1 / 2016-02-13 ================== - [fix] `eslint` peerDep should not include breaking changes diff --git a/packages/eslint-config-airbnb/package.json b/packages/eslint-config-airbnb/package.json index 6b5cad58b5..dd54ae754e 100644 --- a/packages/eslint-config-airbnb/package.json +++ b/packages/eslint-config-airbnb/package.json @@ -43,14 +43,14 @@ "homepage": "https://github.com/airbnb/javascript", "devDependencies": { "babel-tape-runner": "1.2.0", - "eslint": "^1.10.3", - "eslint-plugin-react": "^3.16.1", + "eslint": "^2.2.0", + "eslint-plugin-react": "^4.0.0", "react": "^0.14.7", "tape": "^4.4.0", "parallelshell": "^2.0.0" }, "peerDependencies": { - "eslint": "^1.0.0", - "eslint-plugin-react": "^3.16.1" + "eslint": "^2.2.0", + "eslint-plugin-react": "^4.0.0" } } diff --git a/packages/eslint-config-airbnb/rules/best-practices.js b/packages/eslint-config-airbnb/rules/best-practices.js index a221d4d999..6f66792478 100644 --- a/packages/eslint-config-airbnb/rules/best-practices.js +++ b/packages/eslint-config-airbnb/rules/best-practices.js @@ -2,6 +2,9 @@ module.exports = { 'rules': { // enforces getter/setter pairs in objects 'accessor-pairs': 0, + // enforces return statements in callbacks of array's methods + // http://eslint.org/docs/rules/array-callback-return + 'array-callback-return': 2, // treat var statements as if they were block scoped 'block-scoped-var': 2, // specify the maximum cyclomatic complexity allowed in a program @@ -20,6 +23,9 @@ module.exports = { 'eqeqeq': 2, // make sure for-in loops have an if statement 'guard-for-in': 2, + // Blacklist certain identifiers to prevent them being used + // http://eslint.org/docs/rules/id-blacklist + 'id-blacklist': 0, // disallow the use of alert, confirm, and prompt 'no-alert': 1, // disallow use of arguments.caller or arguments.callee @@ -31,8 +37,9 @@ module.exports = { '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 Unnecessary Labels + // http://eslint.org/docs/rules/no-extra-label + 'no-extra-label': 2, // disallow comparisons to null without a type-checking operator 'no-eq-null': 0, // disallow use of eval() @@ -53,8 +60,8 @@ module.exports = { 'no-invalid-this': 0, // disallow usage of __iterator__ property 'no-iterator': 2, - // disallow use of labeled statements - 'no-labels': 2, + // disallow use of labels for anything other then loops and switches + 'no-labels': [2, { 'allowLoop': false, 'allowSwitch': false }], // disallow unnecessary nested blocks 'no-lone-blocks': 2, // disallow creation of functions within loops @@ -96,8 +103,14 @@ module.exports = { 'no-sequences': 2, // restrict what can be thrown as an exception 'no-throw-literal': 2, + // disallow unmodified conditions of loops + // http://eslint.org/docs/rules/no-unmodified-loop-condition + 'no-unmodified-loop-condition': 0, // disallow usage of expressions in statement position 'no-unused-expressions': 2, + // disallow unused labels + // http://eslint.org/docs/rules/no-unused-labels + 'no-unused-labels': 2, // disallow unnecessary .call() and .apply() 'no-useless-call': 0, // disallow use of void operator diff --git a/packages/eslint-config-airbnb/rules/es6.js b/packages/eslint-config-airbnb/rules/es6.js index f28a436ba3..e88b2d5059 100644 --- a/packages/eslint-config-airbnb/rules/es6.js +++ b/packages/eslint-config-airbnb/rules/es6.js @@ -1,25 +1,15 @@ module.exports = { 'env': { - 'es6': false + 'es6': true }, - '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 + 'parserOptions': { + 'ecmaVersion': 6, + 'sourceType': 'module', + 'ecmaFeatures': { + 'jsx': true, + 'generators': false, + 'objectLiteralDuplicateProperties': false + } }, 'rules': { // enforces no braces where they can be omitted @@ -38,12 +28,24 @@ module.exports = { 'generator-star-spacing': 0, // disallow modifying variables of class declarations 'no-class-assign': 0, + // disallow arrow functions where they could be confused with comparisons + // http://eslint.org/docs/rules/no-confusing-arrow + 'no-confusing-arrow': 2, // disallow modifying variables that are declared using const 'no-const-assign': 2, + // disallow symbol constructor + // http://eslint.org/docs/rules/no-new-symbol + 'no-new-symbol': 2, + // disallow specific imports + // http://eslint.org/docs/rules/no-restricted-imports + 'no-restricted-imports': 0, // 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, + // disallow unnecessary constructor + // http://eslint.org/docs/rules/no-useless-constructor + 'no-useless-constructor': 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'], @@ -55,10 +57,22 @@ module.exports = { 'prefer-spread': 0, // suggest using Reflect methods where applicable 'prefer-reflect': 0, + // use rest parameters instead of arguments + // http://eslint.org/docs/rules/prefer-rest-params + 'prefer-rest-params': 2, // suggest using template literals instead of string concatenation // http://eslint.org/docs/rules/prefer-template 'prefer-template': 2, // disallow generator functions that do not have yield - 'require-yield': 0 + 'require-yield': 0, + // import sorting + // http://eslint.org/docs/rules/sort-imports + 'sort-imports': 0, + // enforce usage of spacing in template strings + // http://eslint.org/docs/rules/template-curly-spacing + 'template-curly-spacing': 2, + // enforce spacing around the * in yield* expressions + // http://eslint.org/docs/rules/yield-star-spacing + 'yield-star-spacing': [2, 'after'] } }; diff --git a/packages/eslint-config-airbnb/rules/react.js b/packages/eslint-config-airbnb/rules/react.js index e1e1c25993..b7a9889e69 100644 --- a/packages/eslint-config-airbnb/rules/react.js +++ b/packages/eslint-config-airbnb/rules/react.js @@ -10,7 +10,7 @@ module.exports = { '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 }], + 'react/display-name': [0, { 'ignoreTranspilerName': 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'] }], @@ -54,8 +54,8 @@ module.exports = { // 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, { + // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/sort-prop-types.md + 'react/sort-prop-types': [0, { 'ignoreCase': false, 'callbacksLast': false, }], @@ -116,10 +116,14 @@ module.exports = { // 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 spaces before the closing bracket of self-closing JSX elements + // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-space-before-closing.md + 'react/jsx-space-before-closing': [2, 'always'], // Enforce component methods order // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/sort-comp.md 'react/sort-comp': [2, { 'order': [ + 'static-methods', 'lifecycle', '/^on.+$/', '/^(get|set)(?!(InitialState$|DefaultProps$|ChildContext$)).+$/', diff --git a/packages/eslint-config-airbnb/rules/style.js b/packages/eslint-config-airbnb/rules/style.js index 25c5326857..c147aae8b7 100644 --- a/packages/eslint-config-airbnb/rules/style.js +++ b/packages/eslint-config-airbnb/rules/style.js @@ -31,6 +31,16 @@ module.exports = { 'jsx-quotes': [2, 'prefer-double'], // enforces spacing between keys and values in object literal properties 'key-spacing': [2, { 'beforeColon': false, 'afterColon': true }], + // require a space before & after certain keywords + 'keyword-spacing': [2, { + 'before': true, + 'after': true, + 'overrides': { + 'return': { 'after': true }, + 'throw': { 'after': true }, + 'case': { 'after': true } + } + }], // enforces empty lines around comments 'lines-around-comment': 0, // disallow mixed 'LF' and 'CRLF' as linebreaks @@ -49,6 +59,10 @@ module.exports = { 'new-parens': 0, // allow/disallow an empty newline after var statement 'newline-after-var': 0, + // enforces new line after each method call in the chain to make it + // more readable and easy to maintain + // http://eslint.org/docs/rules/newline-per-chained-call + 'newline-per-chained-call': [2, { 'ignoreChainWithDepth': 3 }], // disallow use of the Array constructor 'no-array-constructor': 0, // disallow use of the continue statement @@ -77,10 +91,16 @@ module.exports = { // also, prefer `a || b` over `a ? a : b` // http://eslint.org/docs/rules/no-unneeded-ternary 'no-unneeded-ternary': [2, { 'defaultAssignment': false }], + // disallow whitespace before properties + // http://eslint.org/docs/rules/no-whitespace-before-property + 'no-whitespace-before-property': 2, // require padding inside curly braces 'object-curly-spacing': [2, 'always'], // allow just one var statement per function 'one-var': [2, 'never'], + // require a newline around variable declaration + // http://eslint.org/docs/rules/one-var-declaration-per-line + 'one-var-declaration-per-line': [2, 'always'], // require assignment operator shorthand where possible or prohibit it entirely 'operator-assignment': 0, // enforce operators to be placed before or after line breaks @@ -100,10 +120,6 @@ module.exports = { '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 @@ -113,8 +129,6 @@ module.exports = { '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 diff --git a/packages/eslint-config-airbnb/rules/variables.js b/packages/eslint-config-airbnb/rules/variables.js index 59914313f9..3bfcc83fde 100644 --- a/packages/eslint-config-airbnb/rules/variables.js +++ b/packages/eslint-config-airbnb/rules/variables.js @@ -6,8 +6,14 @@ module.exports = { 'no-catch-shadow': 0, // disallow deletion of variables 'no-delete-var': 2, + // disallow var and named functions in global scope + // http://eslint.org/docs/rules/no-implicit-globals + 'no-implicit-globals': 0, // disallow labels that share a name with a variable 'no-label-var': 0, + // disallow self assignment + // http://eslint.org/docs/rules/no-self-assign + 'no-self-assign': 2, // disallow shadowing of names such as arguments 'no-shadow-restricted-names': 2, // disallow declaration of variables already declared in the outer scope diff --git a/packages/eslint-config-airbnb/test/test-react-order.js b/packages/eslint-config-airbnb/test/test-react-order.js index 77448cf86a..f5b2d452fe 100644 --- a/packages/eslint-config-airbnb/test/test-react-order.js +++ b/packages/eslint-config-airbnb/test/test-react-order.js @@ -14,7 +14,8 @@ const cli = new CLIEngine({ function lint(text) { // @see http://eslint.org/docs/developer-guide/nodejs-api.html#executeonfiles // @see http://eslint.org/docs/developer-guide/nodejs-api.html#executeontext - return cli.executeOnText(text).results[0]; + const linter = cli.executeOnText(text); + return linter.results[0]; } function wrapComponent(body) {