From b48c721f7f0e5108bd7b7218dca3f7fe2c4f538f Mon Sep 17 00:00:00 2001 From: Nick Hwang Date: Mon, 12 Oct 2015 15:01:04 -0400 Subject: [PATCH 01/54] Begin HubSpot's version --- README.md | 11 ++++---- es5/README.md | 8 +++--- linters/README.md | 2 +- package.json | 19 ++++++++----- packages/eslint-config-airbnb/index.js | 7 ----- packages/eslint-config-airbnb/legacy.js | 21 --------------- .../node_modules/eslint-config-airbnb | 1 - .../.eslintrc | 0 .../README.md | 27 ++++++++++--------- .../base.js | 4 +-- packages/eslint-config-hubspot/index.js | 7 +++++ packages/eslint-config-hubspot/legacy.js | 21 +++++++++++++++ .../package.json | 17 +++++++----- .../rules/best-practices.js | 0 .../rules/errors.js | 0 .../rules/es6.js | 0 .../rules/legacy.js | 0 .../rules/node.js | 0 .../rules/react.js | 0 .../rules/strict.js | 0 .../rules/style.js | 0 .../rules/variables.js | 0 .../test/.eslintrc | 0 .../test/test-base.js | 0 .../test/test-react-order.js | 0 react/README.md | 7 +++-- 26 files changed, 85 insertions(+), 67 deletions(-) delete mode 100644 packages/eslint-config-airbnb/index.js delete mode 100644 packages/eslint-config-airbnb/legacy.js delete mode 120000 packages/eslint-config-airbnb/node_modules/eslint-config-airbnb rename packages/{eslint-config-airbnb => eslint-config-hubspot}/.eslintrc (100%) rename packages/{eslint-config-airbnb => eslint-config-hubspot}/README.md (67%) rename packages/{eslint-config-airbnb => eslint-config-hubspot}/base.js (52%) create mode 100644 packages/eslint-config-hubspot/index.js create mode 100644 packages/eslint-config-hubspot/legacy.js rename packages/{eslint-config-airbnb => eslint-config-hubspot}/package.json (58%) rename packages/{eslint-config-airbnb => eslint-config-hubspot}/rules/best-practices.js (100%) rename packages/{eslint-config-airbnb => eslint-config-hubspot}/rules/errors.js (100%) rename packages/{eslint-config-airbnb => eslint-config-hubspot}/rules/es6.js (100%) rename packages/{eslint-config-airbnb => eslint-config-hubspot}/rules/legacy.js (100%) rename packages/{eslint-config-airbnb => eslint-config-hubspot}/rules/node.js (100%) rename packages/{eslint-config-airbnb => eslint-config-hubspot}/rules/react.js (100%) rename packages/{eslint-config-airbnb => eslint-config-hubspot}/rules/strict.js (100%) rename packages/{eslint-config-airbnb => eslint-config-hubspot}/rules/style.js (100%) rename packages/{eslint-config-airbnb => eslint-config-hubspot}/rules/variables.js (100%) rename packages/{eslint-config-airbnb => eslint-config-hubspot}/test/.eslintrc (100%) rename packages/{eslint-config-airbnb => eslint-config-hubspot}/test/test-base.js (100%) rename packages/{eslint-config-airbnb => eslint-config-hubspot}/test/test-react-order.js (100%) diff --git a/README.md b/README.md index fdcdccae2b..c53adbb43f 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,11 @@ -# Airbnb JavaScript Style Guide() { +# HubSpot JavaScript Style Guide() { -*A mostly reasonable approach to JavaScript* +> Forked from [Airbnb's Style Guide](https://github.com/airbnb/javascript) -[![Downloads](https://img.shields.io/npm/dm/eslint-config-airbnb.svg)](https://www.npmjs.com/package/eslint-config-airbnb) -[![Gitter](https://badges.gitter.im/Join Chat.svg)](https://gitter.im/airbnb/javascript?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) +*HubSpot's version of a mostly reasonable approach to JavaScript* -Other Style Guides + +Other Style Guides (from Airbnb) - [ES5](es5/) - [React](react/) - [CSS & Sass](https://github.com/airbnb/css) @@ -2057,6 +2057,7 @@ Other Style Guides - Code Style Linters + [ESlint](http://eslint.org/) - [Airbnb Style .eslintrc](https://github.com/airbnb/javascript/blob/master/linters/.eslintrc) + + [ESlint](http://eslint.org/) - [HubSpot Style .eslintrc](https://github.com/HubSpot/javascript/blob/master/linters/.eslintrc) + [JSHint](http://www.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) diff --git a/es5/README.md b/es5/README.md index 2d24f1a4a2..f95f25d6de 100644 --- a/es5/README.md +++ b/es5/README.md @@ -1,8 +1,9 @@ -[![Gitter](https://badges.gitter.im/Join Chat.svg)](https://gitter.im/airbnb/javascript?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) +# HubSpot JavaScript Style Guide() { -# Airbnb JavaScript Style Guide() { +> Forked from [Airbnb's Style Guide](https://github.com/airbnb/javascript) + +*HubSpot's version of a mostly reasonable approach to JavaScript* -*A mostly reasonable approach to JavaScript* ## Table of Contents @@ -1648,6 +1649,7 @@ - **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) + - **HubSpot**: [HubSpot/javascript](https://github.com/HubSpot/javascript) - **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) diff --git a/linters/README.md b/linters/README.md index 1deac701c7..49acca5513 100644 --- a/linters/README.md +++ b/linters/README.md @@ -4,7 +4,7 @@ Our `.eslintrc` requires the following NPM packages: ``` npm install --save-dev \ - eslint-config-airbnb \ + eslint-config-hubspot \ eslint \ babel-eslint \ eslint-plugin-react diff --git a/package.json b/package.json index dc0225dc08..c0dc84ed8b 100644 --- a/package.json +++ b/package.json @@ -1,14 +1,14 @@ { - "name": "airbnb-style", + "name": "hubspot-style", "version": "2.0.0", - "description": "A mostly reasonable approach to JavaScript.", + "description": "HubSpot's version of a mostly reasonable approach to JavaScript", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", - "publish-all": "npm publish && cd ./packages/eslint-config-airbnb && npm publish" + "publish-all": "npm publish && cd ./packages/eslint-config-hubspot && npm publish" }, "repository": { "type": "git", - "url": "https://github.com/airbnb/javascript.git" + "url": "https://github.com/HubSpot/javascript.git" }, "keywords": [ "style guide", @@ -17,12 +17,17 @@ "es6", "es2015", "react", - "jsx" + "jsx", + "hubspot" ], "author": "Harrison Shoff (https://twitter.com/hshoff)", + "contributors": [ + "Ben Anderson ", + "Nicholas Hwang " + ], "license": "MIT", "bugs": { - "url": "https://github.com/airbnb/javascript/issues" + "url": "https://github.com/HubSpot/javascript/issues" }, - "homepage": "https://github.com/airbnb/javascript" + "homepage": "https://github.com/HubSpot/javascript" } diff --git a/packages/eslint-config-airbnb/index.js b/packages/eslint-config-airbnb/index.js deleted file mode 100644 index 46d601fe3f..0000000000 --- a/packages/eslint-config-airbnb/index.js +++ /dev/null @@ -1,7 +0,0 @@ -module.exports = { - 'extends': [ - 'eslint-config-airbnb/base', - 'eslint-config-airbnb/rules/react', - ], - rules: {} -}; diff --git a/packages/eslint-config-airbnb/legacy.js b/packages/eslint-config-airbnb/legacy.js deleted file mode 100644 index 83a4931e84..0000000000 --- a/packages/eslint-config-airbnb/legacy.js +++ /dev/null @@ -1,21 +0,0 @@ -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/strict', - 'eslint-config-airbnb/rules/style', - 'eslint-config-airbnb/rules/variables' - ], - 'env': { - 'browser': true, - 'node': true, - 'amd': false, - 'mocha': false, - 'jasmine': false - }, - 'ecmaFeatures': {}, - 'globals': {}, - 'rules': {} -}; diff --git a/packages/eslint-config-airbnb/node_modules/eslint-config-airbnb b/packages/eslint-config-airbnb/node_modules/eslint-config-airbnb deleted file mode 120000 index a96aa0ea9d..0000000000 --- a/packages/eslint-config-airbnb/node_modules/eslint-config-airbnb +++ /dev/null @@ -1 +0,0 @@ -.. \ No newline at end of file diff --git a/packages/eslint-config-airbnb/.eslintrc b/packages/eslint-config-hubspot/.eslintrc similarity index 100% rename from packages/eslint-config-airbnb/.eslintrc rename to packages/eslint-config-hubspot/.eslintrc diff --git a/packages/eslint-config-airbnb/README.md b/packages/eslint-config-hubspot/README.md similarity index 67% rename from packages/eslint-config-airbnb/README.md rename to packages/eslint-config-hubspot/README.md index f142c5a894..b109b89ba9 100644 --- a/packages/eslint-config-airbnb/README.md +++ b/packages/eslint-config-hubspot/README.md @@ -1,34 +1,37 @@ -# eslint-config-airbnb +# eslint-config-hubspot + +> Forked from [Airbnb's Style Guide](https://github.com/airbnb/javascript) + +This package provides HubSpot's .eslintrc as an extensible shared config. -This package provides Airbnb's .eslintrc as an extensible shared config. ## Usage We export three ESLint configurations for your usage. -### eslint-config-airbnb +### eslint-config-hubspot Our default export contains all of our ESLint rules, including EcmaScript 6+ and React. It requires `eslint`, `babel-eslint`, and `eslint-plugin-react`. -1. `npm install --save-dev eslint-config-airbnb babel-eslint eslint-plugin-react eslint` -2. add `"extends": "airbnb"` to your .eslintrc +1. `npm install --save-dev eslint-config-hubspot babel-eslint eslint-plugin-react eslint` +2. add `"extends": "hubspot"` to your .eslintrc -### eslint-config-airbnb/base +### eslint-config-hubspot/base Lints ES6+ but does not lint React. Requires `eslint` and `babel-eslint`. -1. `npm install --save-dev eslint-config-airbnb babel-eslint eslint` -2. add `"extends": "airbnb/base"` to your .eslintrc +1. `npm install --save-dev eslint-config-hubspot babel-eslint eslint` +2. add `"extends": "hubspot/base"` to your .eslintrc -### eslint-config-airbnb/legacy +### eslint-config-hubspot/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 +1. `npm install --save-dev eslint-config-hubspot eslint` +2. add `"extends": "hubspot/legacy"` to your .eslintrc -See [Airbnb's Javascript styleguide](https://github.com/airbnb/javascript) and +See [HubSpot's Javascript styleguide](https://github.com/HubSpot/javascript) and the [ESlint config docs](http://eslint.org/docs/user-guide/configuring#extending-configuration-files) for more information. diff --git a/packages/eslint-config-airbnb/base.js b/packages/eslint-config-hubspot/base.js similarity index 52% rename from packages/eslint-config-airbnb/base.js rename to packages/eslint-config-hubspot/base.js index ff9904e775..693f0fbc96 100644 --- a/packages/eslint-config-airbnb/base.js +++ b/packages/eslint-config-hubspot/base.js @@ -1,7 +1,7 @@ module.exports = { 'extends': [ - 'eslint-config-airbnb/legacy', - 'eslint-config-airbnb/rules/es6', + 'eslint-config-hubspot/legacy', + 'eslint-config-hubspot/rules/es6', ], 'parser': 'babel-eslint', 'rules': {} diff --git a/packages/eslint-config-hubspot/index.js b/packages/eslint-config-hubspot/index.js new file mode 100644 index 0000000000..2cc8b0972e --- /dev/null +++ b/packages/eslint-config-hubspot/index.js @@ -0,0 +1,7 @@ +module.exports = { + 'extends': [ + 'eslint-config-hubspot/base', + 'eslint-config-hubspot/rules/react', + ], + rules: {} +}; diff --git a/packages/eslint-config-hubspot/legacy.js b/packages/eslint-config-hubspot/legacy.js new file mode 100644 index 0000000000..e989c491e1 --- /dev/null +++ b/packages/eslint-config-hubspot/legacy.js @@ -0,0 +1,21 @@ +module.exports = { + 'extends': [ + 'eslint-config-hubspot/rules/best-practices', + 'eslint-config-hubspot/rules/errors', + 'eslint-config-hubspot/rules/legacy', + 'eslint-config-hubspot/rules/node', + 'eslint-config-hubspot/rules/strict', + 'eslint-config-hubspot/rules/style', + 'eslint-config-hubspot/rules/variables' + ], + '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-hubspot/package.json similarity index 58% rename from packages/eslint-config-airbnb/package.json rename to packages/eslint-config-hubspot/package.json index e7cd1bcc3c..19d2f3c11d 100644 --- a/packages/eslint-config-airbnb/package.json +++ b/packages/eslint-config-hubspot/package.json @@ -1,7 +1,7 @@ { - "name": "eslint-config-airbnb", + "name": "eslint-config-hubspot", "version": "0.1.0", - "description": "Airbnb's ESLint config, following our styleguide", + "description": "HubSpot's ESLint config, following our styleguide", "main": "index.js", "scripts": { "lint": "eslint .", @@ -9,7 +9,7 @@ }, "repository": { "type": "git", - "url": "https://github.com/airbnb/javascript" + "url": "https://github.com/HubSpot/javascript" }, "keywords": [ "eslint", @@ -17,14 +17,19 @@ "config", "airbnb", "javascript", - "styleguide" + "styleguide", + "hubspot" ], "author": "Jake Teton-Landis (https://twitter.com/@jitl)", + "contributors": [ + "Ben Anderson ", + "Nicholas Hwang " + ], "license": "MIT", "bugs": { - "url": "https://github.com/airbnb/javascript/issues" + "url": "https://github.com/HubSpot/javascript/issues" }, - "homepage": "https://github.com/airbnb/javascript", + "homepage": "https://github.com/HubSpot/javascript", "devDependencies": { "babel-eslint": "4.1.3", "babel-tape-runner": "1.2.0", diff --git a/packages/eslint-config-airbnb/rules/best-practices.js b/packages/eslint-config-hubspot/rules/best-practices.js similarity index 100% rename from packages/eslint-config-airbnb/rules/best-practices.js rename to packages/eslint-config-hubspot/rules/best-practices.js diff --git a/packages/eslint-config-airbnb/rules/errors.js b/packages/eslint-config-hubspot/rules/errors.js similarity index 100% rename from packages/eslint-config-airbnb/rules/errors.js rename to packages/eslint-config-hubspot/rules/errors.js diff --git a/packages/eslint-config-airbnb/rules/es6.js b/packages/eslint-config-hubspot/rules/es6.js similarity index 100% rename from packages/eslint-config-airbnb/rules/es6.js rename to packages/eslint-config-hubspot/rules/es6.js diff --git a/packages/eslint-config-airbnb/rules/legacy.js b/packages/eslint-config-hubspot/rules/legacy.js similarity index 100% rename from packages/eslint-config-airbnb/rules/legacy.js rename to packages/eslint-config-hubspot/rules/legacy.js diff --git a/packages/eslint-config-airbnb/rules/node.js b/packages/eslint-config-hubspot/rules/node.js similarity index 100% rename from packages/eslint-config-airbnb/rules/node.js rename to packages/eslint-config-hubspot/rules/node.js diff --git a/packages/eslint-config-airbnb/rules/react.js b/packages/eslint-config-hubspot/rules/react.js similarity index 100% rename from packages/eslint-config-airbnb/rules/react.js rename to packages/eslint-config-hubspot/rules/react.js diff --git a/packages/eslint-config-airbnb/rules/strict.js b/packages/eslint-config-hubspot/rules/strict.js similarity index 100% rename from packages/eslint-config-airbnb/rules/strict.js rename to packages/eslint-config-hubspot/rules/strict.js diff --git a/packages/eslint-config-airbnb/rules/style.js b/packages/eslint-config-hubspot/rules/style.js similarity index 100% rename from packages/eslint-config-airbnb/rules/style.js rename to packages/eslint-config-hubspot/rules/style.js diff --git a/packages/eslint-config-airbnb/rules/variables.js b/packages/eslint-config-hubspot/rules/variables.js similarity index 100% rename from packages/eslint-config-airbnb/rules/variables.js rename to packages/eslint-config-hubspot/rules/variables.js diff --git a/packages/eslint-config-airbnb/test/.eslintrc b/packages/eslint-config-hubspot/test/.eslintrc similarity index 100% rename from packages/eslint-config-airbnb/test/.eslintrc rename to packages/eslint-config-hubspot/test/.eslintrc diff --git a/packages/eslint-config-airbnb/test/test-base.js b/packages/eslint-config-hubspot/test/test-base.js similarity index 100% rename from packages/eslint-config-airbnb/test/test-base.js rename to packages/eslint-config-hubspot/test/test-base.js diff --git a/packages/eslint-config-airbnb/test/test-react-order.js b/packages/eslint-config-hubspot/test/test-react-order.js similarity index 100% rename from packages/eslint-config-airbnb/test/test-react-order.js rename to packages/eslint-config-hubspot/test/test-react-order.js diff --git a/react/README.md b/react/README.md index dd5592f4ed..d98997e44d 100644 --- a/react/README.md +++ b/react/README.md @@ -1,6 +1,9 @@ -# Airbnb React/JSX Style Guide +# HubSpot React/JSX Style Guide + +> Forked from [Airbnb's React/JSX Style Guide](https://github.com/airbnb/javascript/blob/master/react/README.md) + +*HubSpot's version of a mostly reasonable approach to React and JSX* -*A mostly reasonable approach to React and JSX* ## Table of Contents From 94be3dc7732e2245f2a665d9abb1ab7fa7154286 Mon Sep 17 00:00:00 2001 From: Nick Hwang Date: Mon, 12 Oct 2015 17:24:49 -0400 Subject: [PATCH 02/54] Update rules to reflect HubSpot styles --- README.md | 66 +++++ package.json | 2 +- packages/eslint-config-hubspot/.eslintrc | 2 +- packages/eslint-config-hubspot/base.js | 6 +- packages/eslint-config-hubspot/index.js | 2 +- packages/eslint-config-hubspot/legacy.js | 20 +- .../eslint-config-hubspot/rules/errors.js | 2 +- packages/eslint-config-hubspot/rules/react.js | 35 ++- packages/eslint-config-hubspot/rules/style.js | 6 +- react/README.md | 260 ++++++++++++++++-- 10 files changed, 356 insertions(+), 45 deletions(-) diff --git a/README.md b/README.md index c53adbb43f..259b7c185e 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,7 @@ Other Style Guides (from Airbnb) 1. [ECMAScript 5 Compatibility](#ecmascript-5-compatibility) 1. [ECMAScript 6 Styles](#ecmascript-6-styles) 1. [Testing](#testing) + 1. [HubSpot Variants](#hubspot-variants) 1. [Performance](#performance) 1. [Resources](#resources) 1. [In the Wild](#in-the-wild) @@ -2026,6 +2027,71 @@ Other Style Guides (from Airbnb) **[⬆ back to top](#table-of-contents)** +## HubSpot Variants + + - [29.1](#29.1) Addendum to [Additional trailing comma](#19.2): **Don't care.** + + > Airbnb encourages multiline trailing commas and makes a good point about it below, but either should be okay as long it's consistent. + + ```javascript + // okay + const hero = { + firstName: 'Dana', + lastName: 'Scully' + }; + + const heroes = [ + 'Batman', + 'Superman' + ]; + + // okay + const hero = { + firstName: 'Dana', + lastName: 'Scully', + }; + + const heroes = [ + 'Batman', + 'Superman', + ]; + ``` + + + - [29.2](#29.2) Variable names should be at least 2 characters long, except `e` and `i` which are commonly used + + ```javascript + // bad + const n = 24; + + // good + const theAnswer = 24; + + // okay + const e = event; + e.preventDefault(); + + // okay + for (let i = 0; i < 24; ++i) { + magic(i); + } + ``` + + - [29.3](#29.3) Addendum to [using PascalCase](#22.3). Constructors require a capital letters, but functions can be capitalize too. The main reason for the latter is for libraries like `Immutable` which allow (and encourage?) initializing objects without `new` + + + ```javascript + // okay + const mapInstance = new Map(); + + // okay + const mapInstance = Map(); + ``` + + +**[⬆ back to top](#table-of-contents)** + + ## Performance - [On Layout & Web Performance](http://kellegous.com/j/2013/01/26/layout-performance/) diff --git a/package.json b/package.json index c0dc84ed8b..8bd573d478 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "HubSpot's version of a mostly reasonable approach to JavaScript", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", - "publish-all": "npm publish && cd ./packages/eslint-config-hubspot && npm publish" + "publish-all": "cd ./packages/eslint-config-hubspot && npm publish" }, "repository": { "type": "git", diff --git a/packages/eslint-config-hubspot/.eslintrc b/packages/eslint-config-hubspot/.eslintrc index 4b3b1fa429..a4c9543e4b 100644 --- a/packages/eslint-config-hubspot/.eslintrc +++ b/packages/eslint-config-hubspot/.eslintrc @@ -1,5 +1,5 @@ { - "extends": "airbnb", + "extends": "hubspot", "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. diff --git a/packages/eslint-config-hubspot/base.js b/packages/eslint-config-hubspot/base.js index 693f0fbc96..c4ebeb7e8f 100644 --- a/packages/eslint-config-hubspot/base.js +++ b/packages/eslint-config-hubspot/base.js @@ -1,8 +1,8 @@ module.exports = { - 'extends': [ + extends: [ 'eslint-config-hubspot/legacy', 'eslint-config-hubspot/rules/es6', ], - 'parser': 'babel-eslint', - 'rules': {} + parser: 'babel-eslint', + rules: {} }; diff --git a/packages/eslint-config-hubspot/index.js b/packages/eslint-config-hubspot/index.js index 2cc8b0972e..a89c69aab8 100644 --- a/packages/eslint-config-hubspot/index.js +++ b/packages/eslint-config-hubspot/index.js @@ -1,5 +1,5 @@ module.exports = { - 'extends': [ + extends: [ 'eslint-config-hubspot/base', 'eslint-config-hubspot/rules/react', ], diff --git a/packages/eslint-config-hubspot/legacy.js b/packages/eslint-config-hubspot/legacy.js index e989c491e1..8992fcd2df 100644 --- a/packages/eslint-config-hubspot/legacy.js +++ b/packages/eslint-config-hubspot/legacy.js @@ -1,5 +1,5 @@ module.exports = { - 'extends': [ + extends: [ 'eslint-config-hubspot/rules/best-practices', 'eslint-config-hubspot/rules/errors', 'eslint-config-hubspot/rules/legacy', @@ -8,14 +8,14 @@ module.exports = { 'eslint-config-hubspot/rules/style', 'eslint-config-hubspot/rules/variables' ], - 'env': { - 'browser': true, - 'node': true, - 'amd': false, - 'mocha': false, - 'jasmine': false + env: { + browser: true, + node: true, + amd: false, + mocha: false, + jasmine: false }, - 'ecmaFeatures': {}, - 'globals': {}, - 'rules': {} + ecmaFeatures: {}, + globals: {}, + rules: {} }; diff --git a/packages/eslint-config-hubspot/rules/errors.js b/packages/eslint-config-hubspot/rules/errors.js index ec1b1aab0e..58cdc41d41 100644 --- a/packages/eslint-config-hubspot/rules/errors.js +++ b/packages/eslint-config-hubspot/rules/errors.js @@ -1,7 +1,7 @@ module.exports = { 'rules': { // disallow trailing commas in object literals - 'comma-dangle': [2, 'always-multiline'], + 'comma-dangle': 0, // disallow assignment in conditional expressions 'no-cond-assign': [2, 'always'], // disallow use of console diff --git a/packages/eslint-config-hubspot/rules/react.js b/packages/eslint-config-hubspot/rules/react.js index 01aa64c30a..e11b38c3fe 100644 --- a/packages/eslint-config-hubspot/rules/react.js +++ b/packages/eslint-config-hubspot/rules/react.js @@ -10,19 +10,17 @@ module.exports = { // Prevent missing displayName in a React component definition 'react/display-name': 0, // Enforce boolean attributes notation in JSX - 'react/jsx-boolean-value': 2, + 'react/jsx-boolean-value': 0, // Enforce or disallow spaces inside of curly braces in JSX attributes 'react/jsx-curly-spacing': 0, // Prevent duplicate props in JSX 'react/jsx-no-duplicate-props': 0, // Disallow undeclared variables in JSX 'react/jsx-no-undef': 2, - // Enforce quote style for JSX attributes - 'react/jsx-quotes': 0, // Enforce propTypes declarations alphabetical sorting - 'react/jsx-sort-prop-types': 0, + 'react/jsx-sort-prop-types': 2, // Enforce props alphabetical sorting - 'react/jsx-sort-props': 0, + 'react/jsx-sort-props': 2, // Prevent React to be incorrectly marked as unused 'react/jsx-uses-react': 2, // Prevent variables used in JSX to be incorrectly marked as unused @@ -49,12 +47,33 @@ module.exports = { 'react/sort-comp': [2, { 'order': [ 'lifecycle', - '/^on.+$/', - '/^(get|set)(?!(InitialState$|DefaultProps$|ChildContext$)).+$/', 'everything-else', '/^render.+$/', 'render' - ] + ], + 'group': { + 'lifecycle': [ + 'displayName', + 'mixins', + 'propTypes', + 'contextTypes', + 'childContextTypes', + 'statics', + 'defaultProps', + 'constructor', + 'getDefaultProps', + 'getInitialState', + 'state', + 'getChildContext', + 'componentWillMount', + 'componentDidMount', + 'componentWillReceiveProps', + 'shouldComponentUpdate', + 'componentWillUpdate', + 'componentDidUpdate', + 'componentWillUnmount' + ] + } }], // Prevent missing parentheses around multilines JSX 'react/wrap-multilines': 2 diff --git a/packages/eslint-config-hubspot/rules/style.js b/packages/eslint-config-hubspot/rules/style.js index fa22403d8b..53615c2915 100644 --- a/packages/eslint-config-hubspot/rules/style.js +++ b/packages/eslint-config-hubspot/rules/style.js @@ -21,11 +21,11 @@ module.exports = { // 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': [2, {'min': 2, 'properties': 'never'}], + 'id-length': [2, {'min': 2, 'properties': 'never', 'exceptions': ['e', 'i']}], // this option sets a specific tab width for your code 'indent': [2, 2], // specify whether double or single quotes should be used in JSX attributes - 'jsx-quotes': 2, + '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 @@ -35,7 +35,7 @@ module.exports = { // specify the maximum depth callbacks can be nested 'max-nested-callbacks': 0, // require a capital letter for constructors - 'new-cap': [2, {'newIsCap': true}], + 'new-cap': [2, {'newIsCap': true, 'capIsNew': false}], // disallow the omission of parentheses when invoking a constructor with no arguments 'new-parens': 0, // allow/disallow an empty newline after var statement diff --git a/react/README.md b/react/README.md index d98997e44d..17b4854dca 100644 --- a/react/README.md +++ b/react/README.md @@ -14,17 +14,21 @@ 1. [Quotes](#quotes) 1. [Spacing](#spacing) 1. [Props](#props) + 1. [Set State](#set-state) 1. [Parentheses](#parentheses) 1. [Tags](#tags) 1. [Methods](#methods) + 1. [Guidelines](#guidelines) 1. [Ordering](#ordering) + ## Basic Rules - Only include one React component per file. - 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 - Use class extends React.Component unless you have a very good reason to use mixins. @@ -36,7 +40,7 @@ return
; } }); - + // good class Listing extends React.Component { render() { @@ -45,6 +49,7 @@ } ``` + ## Naming - **Extensions**: Use `.jsx` extension for React components. @@ -92,6 +97,7 @@ } ``` + ## Alignment - Follow these alignment styles for JSX syntax @@ -112,12 +118,12 @@ // children get indented normally + anotherSuperLongParam="baz"> ``` + ## Quotes - Always use double quotes (`"`) for JSX attributes, but single quotes for all other JS. @@ -136,8 +142,12 @@ // good + + // good + ``` + ## Spacing - Always include a single space in your self-closing tag. ```javascript @@ -155,6 +165,7 @@ ``` + ## Props - Always use camelCase for prop names. ```javascript @@ -171,6 +182,128 @@ /> ``` + - Use explicit values for Boolean props + ```javascript + // bad (implicit true) + ; + + // super-bad (string value) + ; + + // good (explicit) + ; + ``` + + - List __props__ in alphabetical order, unless you are spreading props and different ordering is required to maintain behavior. + + ```javascript + // bad + ; + + // good + ; + + // meh (introducing spread changes behavior, so do what you must...) + ; + ``` + + + - List _propTypes_ alphabetically + + ```javascript + // bad + var Component = React.createClass({ + propTypes: { + z: React.PropTypes.number, + a: React.PropTypes.any, + b: React.PropTypes.string + } + }); + + // good + var Component = React.createClass({ + propTypes: { + a: React.PropTypes.any, + b: React.PropTypes.string, + z: React.PropTypes.number + } + }); + ``` + + - Declare every prop in `propTypes`. If you use a value on `this.props` anywhere in your component, it should be listed in `propTypes`. + + ```javascript + // bad (missing propType declaration) + export default React.createClass({ + render() { + return
Hello {this.props.name}
; + } + }); + + // good (all props declared) + export default React.createClass({ + propTypes: { + name: React.PropTypes.string, + children: React.PropTypes.node + }, + + render() { + const {children, name} = this.props; + return ( +
+ Hello {name} + {children} +
+ ); + } + }); + ``` + + - Always provide defaults for non-required `propTypes` + + ```javascript + // bad (missing default value for `b` and `z` props) + var Component = React.createClass({ + propTypes: { + a: React.PropTypes.any.isRequired, + b: React.PropTypes.string, + z: React.PropTypes.number + } + }); + + // good + var Component = React.createClass({ + propTypes: { + a: React.PropTypes.any.isRequired, + b: React.PropTypes.string, + z: React.PropTypes.number + }, + + getDefaultProps() { + return { + b: 'something', + z: 0 + } + } + }); + ``` + + +## Set State + - Don't `setState` in `componentDidMount` + + Updating the state after a component mount will trigger a second render() call and can lead to property/layout thrashing. This **does not apply to `setState` in event handlers** added here. + + If you need to do something to change state here, use a function prop that can change state at the top level and pass new data down accordingly. + + + - Don't `setState` in `componentDidUpdate` + + Updating the state after a component update will trigger a second render() call and can lead to property/layout thrashing. + + If you need to do something to change state here, use a function prop that can change state at the top level and pass new data down accordingly. + + ## Parentheses - Wrap JSX tags in parentheses when they span more than one line: ```javascript @@ -197,6 +330,7 @@ } ``` + ## Tags - Always self-close tags that have no children. ```javascript @@ -221,6 +355,7 @@ /> ``` + ## Methods - Do not use underscore prefix for internal methods of a React component. ```javascript @@ -243,10 +378,102 @@ }); ``` + +## GuideLines + +These are guidelines more than rules, and they will likely be more controversial than those listed above. This is where we collaborate :) + + + - Destructure `props` and `state` variables at the top of `render()` + + Instead of spreading your state access all over the place, destructure everything at the top of `render` to make it obvious which data fields are used. + + ```javascript + // bad + export default React.createClass({ + ... + render() { + return ( +
+ {/* access spread throughout component */} + Hello {this.props.name} + {/* stateful helpers... */} + {this.renderHelper()} + {/* transfers props that are intended for this component */} + +
+ ); + } + }); + + // good + export default React.createClass({] + ... + render() { + {/* all data in one place */} + const {children, name, ...other} = this.props; + return ( +
+ Hello {name} + {/* stateless helper functions */} + {this.renderHelper(children)} + {/* only necessary props transferred */} + +
+ ); + } + }); + ``` + + This has the additional benefit of: + + * Keeping your helper methods stateless by passing in values (see below) + * Enabling [props transfer](https://facebook.github.io/react/docs/transferring-props.html#transferring-with-...-in-jsx) using `...` for unused values without triggering warnings for unused vars in render + + - Keep your helper methods stateless + + Prefer to pass props/state values into your helper methods instead of access via `this` in the method body. This enables you to extract them to helper objects without refactoring, as well as easily write automated tests without needing to setup a complete stateful component. + + ```js + // discouraged (stateful method, harder to test and extract/refactor) + export default React.createClass({ + ... + render() { + return ( +
+ {this.renderHelper()} +
+ ); + }, + + renderHelper() { + return `Custom value: ${someRenderingLogic(this.props.value)}`; + } + }); + + + // preferred (stateless function, easy to test and extract/refactor) + export default React.createClass({] + ... + render() { + const {value} = this.props; + return ( +
+ {this.renderHelper(value)} +
+ ); + }, + + renderHelper(value) { + return `Custom value: ${someRenderingLogic(value)}`; + } + }); + ``` + ## Ordering - Ordering for class extends React.Component: - + 1. constructor 1. optional static methods 1. getChildContext @@ -257,36 +484,35 @@ 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. Getters, setters, event handlers, helper methods, etc. + 1. Optional render methods like renderNavigation() or renderProfilePicture() 1. render - - How to define propTypes, defaultProps, contextTypes, etc... + - 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} } } - + Link.propTypes = propTypes; Link.defaultProps = defaultProps; ``` @@ -294,14 +520,15 @@ - Ordering for React.createClass: 1. displayName + 1. mixins 1. propTypes 1. contextTypes 1. childContextTypes - 1. mixins 1. statics 1. defaultProps 1. getDefaultProps 1. getInitialState + 1. state 1. getChildContext 1. componentWillMount 1. componentDidMount @@ -310,9 +537,8 @@ 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. Getters, setters, event handlers, helper methods, etc. + 1. Optional render methods like renderNavigation() or renderProfilePicture() 1. render **[⬆ back to top](#table-of-contents)** From 14d5e4c4918c9ce660d088b5392cc1eb201953e3 Mon Sep 17 00:00:00 2001 From: Nick Hwang Date: Mon, 12 Oct 2015 17:35:39 -0400 Subject: [PATCH 03/54] Fix tests to pass with react ordering --- packages/eslint-config-hubspot/package.json | 2 +- packages/eslint-config-hubspot/test/test-react-order.js | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/eslint-config-hubspot/package.json b/packages/eslint-config-hubspot/package.json index 19d2f3c11d..3681bf9fe2 100644 --- a/packages/eslint-config-hubspot/package.json +++ b/packages/eslint-config-hubspot/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-hubspot", - "version": "0.1.0", + "version": "1.0.0", "description": "HubSpot's ESLint config, following our styleguide", "main": "index.js", "scripts": { diff --git a/packages/eslint-config-hubspot/test/test-react-order.js b/packages/eslint-config-hubspot/test/test-react-order.js index 606f723671..b5ccdcde7b 100644 --- a/packages/eslint-config-hubspot/test/test-react-order.js +++ b/packages/eslint-config-hubspot/test/test-react-order.js @@ -70,7 +70,7 @@ test('validate react prop order', t => { }); t.test('order: when random method after lifecycle methods', t => { - t.plan(2); + t.plan(3); const result = lint(wrapComponent(` componentWillMount() {} componentDidMount() {} @@ -82,7 +82,8 @@ test('validate react prop order', t => { render() { return
; } `)); - t.ok(result.errorCount, 'fails'); - t.equal(result.messages[0].ruleId, 'react/sort-comp', 'fails due to sort'); + t.notOk(result.warningCount, 'no warnings'); + t.notOk(result.errorCount, 'no errors'); + t.deepEquals(result.messages, [], 'no messages in results'); }); }); From 93e52a8901c5ee2e26fc995c19660fb607b51eb2 Mon Sep 17 00:00:00 2001 From: Nick Hwang Date: Mon, 12 Oct 2015 17:45:58 -0400 Subject: [PATCH 04/54] Update packages --- packages/eslint-config-hubspot/package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/eslint-config-hubspot/package.json b/packages/eslint-config-hubspot/package.json index 3681bf9fe2..3893b89db9 100644 --- a/packages/eslint-config-hubspot/package.json +++ b/packages/eslint-config-hubspot/package.json @@ -33,9 +33,9 @@ "devDependencies": { "babel-eslint": "4.1.3", "babel-tape-runner": "1.2.0", - "eslint": "1.5.1", - "eslint-plugin-react": "3.4.2", - "react": "0.13.3", - "tape": "4.2.0" + "eslint": "1.6.0", + "eslint-plugin-react": "3.5.1", + "react": "0.14.0", + "tape": "4.2.1" } } From edcb5a8cf126146c07f1f58993c2fb192f9b611b Mon Sep 17 00:00:00 2001 From: Nick Hwang Date: Mon, 12 Oct 2015 17:51:51 -0400 Subject: [PATCH 05/54] Consistent formatting --- react/README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/react/README.md b/react/README.md index 17b4854dca..31286cef4f 100644 --- a/react/README.md +++ b/react/README.md @@ -208,7 +208,7 @@ ``` - - List _propTypes_ alphabetically + - List __propTypes__ alphabetically ```javascript // bad @@ -488,6 +488,7 @@ These are guidelines more than rules, and they will likely be more controversial 1. Optional render methods like renderNavigation() or renderProfilePicture() 1. render + - How to define propTypes, defaultProps, contextTypes, etc... ```javascript @@ -517,6 +518,7 @@ These are guidelines more than rules, and they will likely be more controversial Link.defaultProps = defaultProps; ``` + - Ordering for React.createClass: 1. displayName From 82b4552b3809730db926704cfdc58180bfdf2ffa Mon Sep 17 00:00:00 2001 From: Nick Hwang Date: Mon, 12 Oct 2015 22:42:01 -0400 Subject: [PATCH 06/54] Fix react ordering --- package.json | 4 ++-- packages/eslint-config-hubspot/package.json | 2 +- packages/eslint-config-hubspot/rules/react.js | 2 -- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 8bd573d478..24a12671b2 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,10 @@ { "name": "hubspot-style", - "version": "2.0.0", + "version": "1.0.1", "description": "HubSpot's version of a mostly reasonable approach to JavaScript", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", - "publish-all": "cd ./packages/eslint-config-hubspot && npm publish" + "publish-all": "npm publish && cd ./packages/eslint-config-hubspot && npm publish" }, "repository": { "type": "git", diff --git a/packages/eslint-config-hubspot/package.json b/packages/eslint-config-hubspot/package.json index 3893b89db9..2c28cf020c 100644 --- a/packages/eslint-config-hubspot/package.json +++ b/packages/eslint-config-hubspot/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-hubspot", - "version": "1.0.0", + "version": "1.0.1", "description": "HubSpot's ESLint config, following our styleguide", "main": "index.js", "scripts": { diff --git a/packages/eslint-config-hubspot/rules/react.js b/packages/eslint-config-hubspot/rules/react.js index e11b38c3fe..e05782d4d2 100644 --- a/packages/eslint-config-hubspot/rules/react.js +++ b/packages/eslint-config-hubspot/rules/react.js @@ -60,10 +60,8 @@ module.exports = { 'childContextTypes', 'statics', 'defaultProps', - 'constructor', 'getDefaultProps', 'getInitialState', - 'state', 'getChildContext', 'componentWillMount', 'componentDidMount', From 9db4e1974dda79bd53b3fd2f0dcf6895d90115a8 Mon Sep 17 00:00:00 2001 From: Nick Hwang Date: Mon, 12 Oct 2015 23:24:00 -0400 Subject: [PATCH 07/54] Fix typo and add more comprehensive spec --- package.json | 2 +- packages/eslint-config-hubspot/package.json | 2 +- packages/eslint-config-hubspot/rules/react.js | 4 +++- .../eslint-config-hubspot/test/test-react-order.js | 13 +++++++++++++ 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 24a12671b2..330d97dc96 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hubspot-style", - "version": "1.0.1", + "version": "1.0.2", "description": "HubSpot's version of a mostly reasonable approach to JavaScript", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", diff --git a/packages/eslint-config-hubspot/package.json b/packages/eslint-config-hubspot/package.json index 2c28cf020c..3591cc3cfe 100644 --- a/packages/eslint-config-hubspot/package.json +++ b/packages/eslint-config-hubspot/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-hubspot", - "version": "1.0.1", + "version": "1.0.2", "description": "HubSpot's ESLint config, following our styleguide", "main": "index.js", "scripts": { diff --git a/packages/eslint-config-hubspot/rules/react.js b/packages/eslint-config-hubspot/rules/react.js index e05782d4d2..1546093fb2 100644 --- a/packages/eslint-config-hubspot/rules/react.js +++ b/packages/eslint-config-hubspot/rules/react.js @@ -51,7 +51,7 @@ module.exports = { '/^render.+$/', 'render' ], - 'group': { + 'groups': { 'lifecycle': [ 'displayName', 'mixins', @@ -60,7 +60,9 @@ module.exports = { 'childContextTypes', 'statics', 'defaultProps', + 'constructor', 'getDefaultProps', + 'state', 'getInitialState', 'getChildContext', 'componentWillMount', diff --git a/packages/eslint-config-hubspot/test/test-react-order.js b/packages/eslint-config-hubspot/test/test-react-order.js index b5ccdcde7b..72e4ea9adf 100644 --- a/packages/eslint-config-hubspot/test/test-react-order.js +++ b/packages/eslint-config-hubspot/test/test-react-order.js @@ -37,8 +37,21 @@ test('validate react prop order', t => { t.test('passes a good component', t => { t.plan(3); const result = lint(wrapComponent(` + displayName: '' + mixins: [] + propTypes: {} + contextTypes: {} + childContextTypes: {} + getDefaultProps() {} + getInitialState() {} + getChildContext() {} componentWillMount() {} componentDidMount() {} + componentWillReceiveProps() {} + shouldComponentUpdate() {} + componentWillUpdate() {} + componentDidUpdate() {} + componentWillUnmount() {} setFoo() {} getFoo() {} setBar() {} From d6a8d6b5b0898edc4f545a60e363e2c49af28e55 Mon Sep 17 00:00:00 2001 From: Nick Hwang Date: Tue, 13 Oct 2015 01:02:40 -0400 Subject: [PATCH 08/54] Badges --- README.md | 2 ++ packages/eslint-config-hubspot/README.md | 2 ++ 2 files changed, 4 insertions(+) diff --git a/README.md b/README.md index 259b7c185e..e2dc622a14 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # HubSpot JavaScript Style Guide() { +[![npm version](https://badge.fury.io/js/hubspot-style.svg)](https://badge.fury.io/js/hubspot-style) + > Forked from [Airbnb's Style Guide](https://github.com/airbnb/javascript) *HubSpot's version of a mostly reasonable approach to JavaScript* diff --git a/packages/eslint-config-hubspot/README.md b/packages/eslint-config-hubspot/README.md index b109b89ba9..de83ac6521 100644 --- a/packages/eslint-config-hubspot/README.md +++ b/packages/eslint-config-hubspot/README.md @@ -1,5 +1,7 @@ # eslint-config-hubspot +[![npm version](https://badge.fury.io/js/eslint-config-hubspot.svg)](https://badge.fury.io/js/eslint-config-hubspot) + > Forked from [Airbnb's Style Guide](https://github.com/airbnb/javascript) This package provides HubSpot's .eslintrc as an extensible shared config. From 7454a32c6bf1b22be9c5379996d96cfdd7367740 Mon Sep 17 00:00:00 2001 From: Nick Hwang Date: Tue, 13 Oct 2015 18:17:55 -0400 Subject: [PATCH 09/54] Add more exceptions for short variables --- README.md | 2 +- package.json | 2 +- packages/eslint-config-hubspot/package.json | 2 +- packages/eslint-config-hubspot/rules/style.js | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index e2dc622a14..c5bed0fdcb 100644 --- a/README.md +++ b/README.md @@ -2060,7 +2060,7 @@ Other Style Guides (from Airbnb) ``` - - [29.2](#29.2) Variable names should be at least 2 characters long, except `e` and `i` which are commonly used + - [29.2](#29.2) Variable names should be at least 2 characters long, except `e`, `i`, 'Q', and '$' which are commonly used for event, loop index, Q promise, and jQuery (respectively) ```javascript // bad diff --git a/package.json b/package.json index 330d97dc96..21f3502088 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hubspot-style", - "version": "1.0.2", + "version": "1.0.3", "description": "HubSpot's version of a mostly reasonable approach to JavaScript", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", diff --git a/packages/eslint-config-hubspot/package.json b/packages/eslint-config-hubspot/package.json index 3591cc3cfe..bcb845d053 100644 --- a/packages/eslint-config-hubspot/package.json +++ b/packages/eslint-config-hubspot/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-hubspot", - "version": "1.0.2", + "version": "1.0.3", "description": "HubSpot's ESLint config, following our styleguide", "main": "index.js", "scripts": { diff --git a/packages/eslint-config-hubspot/rules/style.js b/packages/eslint-config-hubspot/rules/style.js index 53615c2915..17ed907907 100644 --- a/packages/eslint-config-hubspot/rules/style.js +++ b/packages/eslint-config-hubspot/rules/style.js @@ -21,7 +21,7 @@ module.exports = { // 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': [2, {'min': 2, 'properties': 'never', 'exceptions': ['e', 'i']}], + 'id-length': [2, {'min': 2, 'properties': 'never', 'exceptions': ['e', 'i', 'Q', '$']}], // this option sets a specific tab width for your code 'indent': [2, 2], // specify whether double or single quotes should be used in JSX attributes From 0d99728d22928c83e25b8188753cd9715eae1d1e Mon Sep 17 00:00:00 2001 From: Nick Hwang Date: Tue, 13 Oct 2015 18:53:18 -0400 Subject: [PATCH 10/54] Minor fix in readme --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c5bed0fdcb..eb0eb7361b 100644 --- a/README.md +++ b/README.md @@ -7,9 +7,11 @@ *HubSpot's version of a mostly reasonable approach to JavaScript* -Other Style Guides (from Airbnb) +Other Style Guides (from HubSpot) - [ES5](es5/) - [React](react/) + +Other Style Guides (from Airbnb) - [CSS & Sass](https://github.com/airbnb/css) - [Ruby](https://github.com/airbnb/ruby) @@ -2060,7 +2062,7 @@ Other Style Guides (from Airbnb) ``` - - [29.2](#29.2) Variable names should be at least 2 characters long, except `e`, `i`, 'Q', and '$' which are commonly used for event, loop index, Q promise, and jQuery (respectively) + - [29.2](#29.2) Variable names should be at least 2 characters long, except `e`, `i`, `Q`, and `$` which are commonly used for event, loop index, Q promise, and jQuery (respectively) ```javascript // bad From 72d00672f117ec969b9f54e6582deb4a93997835 Mon Sep 17 00:00:00 2001 From: Nick Hwang Date: Tue, 13 Oct 2015 23:17:06 -0400 Subject: [PATCH 11/54] Fix another typo --- README.md | 2 +- linters/.eslintrc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index eb0eb7361b..c3156e7bcd 100644 --- a/README.md +++ b/README.md @@ -2126,8 +2126,8 @@ Other Style Guides (from Airbnb) **Tools** - Code Style Linters - + [ESlint](http://eslint.org/) - [Airbnb Style .eslintrc](https://github.com/airbnb/javascript/blob/master/linters/.eslintrc) + [ESlint](http://eslint.org/) - [HubSpot Style .eslintrc](https://github.com/HubSpot/javascript/blob/master/linters/.eslintrc) + + [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) + [JSCS](https://github.com/jscs-dev/node-jscs) - [Airbnb Style Preset](https://github.com/jscs-dev/node-jscs/blob/master/presets/airbnb.json) diff --git a/linters/.eslintrc b/linters/.eslintrc index 9e203a5473..8230cec406 100644 --- a/linters/.eslintrc +++ b/linters/.eslintrc @@ -1,5 +1,5 @@ // Use this file as a starting point for your project's .eslintrc. // Copy this file, and add rule overrides as needed. { - "extends": "airbnb" + "extends": "hubspot" } From 1898ff74efd918ef58bf93bc315cbe7291a7a1f3 Mon Sep 17 00:00:00 2001 From: Nick Hwang Date: Wed, 14 Oct 2015 16:44:59 -0400 Subject: [PATCH 12/54] Move statics closer to top of order --- package.json | 2 +- packages/eslint-config-hubspot/package.json | 2 +- packages/eslint-config-hubspot/rules/best-practices.js | 2 +- packages/eslint-config-hubspot/rules/react.js | 4 +--- 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 21f3502088..ed1b386b17 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hubspot-style", - "version": "1.0.3", + "version": "1.0.4", "description": "HubSpot's version of a mostly reasonable approach to JavaScript", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", diff --git a/packages/eslint-config-hubspot/package.json b/packages/eslint-config-hubspot/package.json index bcb845d053..0c18d6c3f4 100644 --- a/packages/eslint-config-hubspot/package.json +++ b/packages/eslint-config-hubspot/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-hubspot", - "version": "1.0.3", + "version": "1.0.4", "description": "HubSpot's ESLint config, following our styleguide", "main": "index.js", "scripts": { diff --git a/packages/eslint-config-hubspot/rules/best-practices.js b/packages/eslint-config-hubspot/rules/best-practices.js index 9d8199eb77..53c8a047b9 100644 --- a/packages/eslint-config-hubspot/rules/best-practices.js +++ b/packages/eslint-config-hubspot/rules/best-practices.js @@ -66,7 +66,7 @@ module.exports = { 'no-new': 2, // disallow use of new operator for Function object 'no-new-func': 2, - // disallows creating new instances of String,Number, and Boolean + // disallows creating new instances of String, Number, and Boolean 'no-new-wrappers': 2, // disallow use of (old style) octal literals 'no-octal': 2, diff --git a/packages/eslint-config-hubspot/rules/react.js b/packages/eslint-config-hubspot/rules/react.js index 1546093fb2..f03854a055 100644 --- a/packages/eslint-config-hubspot/rules/react.js +++ b/packages/eslint-config-hubspot/rules/react.js @@ -55,14 +55,12 @@ module.exports = { 'lifecycle': [ 'displayName', 'mixins', + 'statics', 'propTypes', 'contextTypes', 'childContextTypes', - 'statics', - 'defaultProps', 'constructor', 'getDefaultProps', - 'state', 'getInitialState', 'getChildContext', 'componentWillMount', From 76c240b57de744c508876934aca3a6cf03953943 Mon Sep 17 00:00:00 2001 From: Nick Hwang Date: Wed, 28 Oct 2015 17:08:01 -0400 Subject: [PATCH 13/54] Add missing `space-before-keywords` rule --- package.json | 2 +- packages/eslint-config-hubspot/package.json | 2 +- packages/eslint-config-hubspot/rules/style.js | 4 +++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index ed1b386b17..5be8c447f4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hubspot-style", - "version": "1.0.4", + "version": "1.0.5", "description": "HubSpot's version of a mostly reasonable approach to JavaScript", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", diff --git a/packages/eslint-config-hubspot/package.json b/packages/eslint-config-hubspot/package.json index 0c18d6c3f4..98e1f4ae8a 100644 --- a/packages/eslint-config-hubspot/package.json +++ b/packages/eslint-config-hubspot/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-hubspot", - "version": "1.0.4", + "version": "1.0.5", "description": "HubSpot's ESLint config, following our styleguide", "main": "index.js", "scripts": { diff --git a/packages/eslint-config-hubspot/rules/style.js b/packages/eslint-config-hubspot/rules/style.js index 17ed907907..43bad28791 100644 --- a/packages/eslint-config-hubspot/rules/style.js +++ b/packages/eslint-config-hubspot/rules/style.js @@ -89,7 +89,9 @@ module.exports = { // sort variables within the same declaration block 'sort-vars': 0, // require a space after certain keywords - 'space-after-keywords': 2, + '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 From e4733595be11f27b02f4fb701661d66c473e63d3 Mon Sep 17 00:00:00 2001 From: Nick Hwang Date: Sun, 29 Nov 2015 14:35:30 -0500 Subject: [PATCH 14/54] Rebase with airbnb/master Other changes: - Also remove alphabetical ordering of React props - Update React specs to use `createClass` rather than ES6 classes - Add `faucet` for prettier TAP output --- README.md | 90 ++++++++++++++----- package.json | 2 +- packages/eslint-config-hubspot/README.md | 24 ++++- packages/eslint-config-hubspot/base.js | 1 - packages/eslint-config-hubspot/package.json | 17 ++-- packages/eslint-config-hubspot/rules/es6.js | 3 +- packages/eslint-config-hubspot/rules/react.js | 9 +- packages/eslint-config-hubspot/rules/style.js | 10 +-- .../test/test-react-order.js | 76 ++++++++-------- react/README.md | 36 -------- 10 files changed, 150 insertions(+), 118 deletions(-) diff --git a/README.md b/README.md index c3156e7bcd..a8cae50e14 100644 --- a/README.md +++ b/README.md @@ -94,7 +94,7 @@ Other Style Guides (from Airbnb) - [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. ```javascript // bad @@ -106,7 +106,7 @@ Other Style Guides (from Airbnb) 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`. @@ -452,7 +452,7 @@ Other Style Guides (from Airbnb) 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)** @@ -1114,7 +1114,7 @@ Other Style Guides (from Airbnb) } ``` - - 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)** @@ -1253,7 +1253,7 @@ Other Style Guides (from Airbnb) } ``` - - [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 @@ -1281,6 +1281,14 @@ Other Style Guides (from Airbnb) 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`. @@ -1516,6 +1524,38 @@ Other Style Guides (from Airbnb) return arr; ``` + - [18.8](#18.8) Do not pad your blocks with blank lines. + + ```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); + } + ``` + **[⬆ back to top](#table-of-contents)** @@ -1625,7 +1665,7 @@ Other Style Guides (from Airbnb) })(); ``` - [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)** @@ -1994,7 +2034,7 @@ Other Style Guides (from Airbnb) ## 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)** @@ -2028,6 +2068,14 @@ Other Style Guides (from Airbnb) } ``` + - [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)** @@ -2098,7 +2146,7 @@ Other Style Guides (from Airbnb) ## 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) @@ -2128,18 +2176,18 @@ Other Style Guides (from Airbnb) - Code Style Linters + [ESlint](http://eslint.org/) - [HubSpot Style .eslintrc](https://github.com/HubSpot/javascript/blob/master/linters/.eslintrc) + [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 @@ -2166,7 +2214,7 @@ Other Style Guides (from Airbnb) - [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 @@ -2176,18 +2224,18 @@ Other Style Guides (from Airbnb) - [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)** @@ -2203,7 +2251,7 @@ Other Style Guides (from Airbnb) - **Avalara**: [avalara/javascript](https://github.com/avalara/javascript) - **Billabong**: [billabong/javascript](https://github.com/billabong/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) @@ -2216,7 +2264,7 @@ Other Style Guides (from Airbnb) - **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) @@ -2224,7 +2272,7 @@ Other Style Guides (from Airbnb) - **Intent Media**: [intentmedia/javascript](https://github.com/intentmedia/javascript) - **Jam3**: [Jam3/Javascript-Code-Conventions](https://github.com/Jam3/Javascript-Code-Conventions) - **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) @@ -2243,7 +2291,7 @@ Other Style Guides (from Airbnb) - **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/package.json b/package.json index 5be8c447f4..7b70ef2948 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hubspot-style", - "version": "1.0.5", + "version": "1.0.6", "description": "HubSpot's version of a mostly reasonable approach to JavaScript", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", diff --git a/packages/eslint-config-hubspot/README.md b/packages/eslint-config-hubspot/README.md index de83ac6521..4c2316f3f7 100644 --- a/packages/eslint-config-hubspot/README.md +++ b/packages/eslint-config-hubspot/README.md @@ -14,16 +14,16 @@ We export three ESLint configurations for your usage. ### eslint-config-hubspot Our default export contains all of our ESLint rules, including EcmaScript 6+ -and React. It requires `eslint`, `babel-eslint`, and `eslint-plugin-react`. +and React. It requires `eslint` and `eslint-plugin-react`. 1. `npm install --save-dev eslint-config-hubspot babel-eslint eslint-plugin-react eslint` 2. add `"extends": "hubspot"` to your .eslintrc ### eslint-config-hubspot/base -Lints ES6+ but does not lint React. Requires `eslint` and `babel-eslint`. +Lints ES6+ but does not lint React. Requires `eslint`. -1. `npm install --save-dev eslint-config-hubspot babel-eslint eslint` +1. `npm install --save-dev eslint-config-hubspot eslint` 2. add `"extends": "hubspot/base"` to your .eslintrc ### eslint-config-hubspot/legacy @@ -49,6 +49,24 @@ You can make sure this module lints with itself using `npm run lint`. ## Changelog +### 1.0.2 +- enable rest params in linter, derp. (#592) +- enforce rule 18.5, ensuring files end with a single newline character. (#578) + +### 1.0.1 + +oops + +### 1.0.0 +- require `eslint` `v1.0.0` or higher +- removes `babel-eslint` dependency + +### 0.1.1 +- 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 - switch to modular rules files courtesy the [eslint-config-default][ecd] diff --git a/packages/eslint-config-hubspot/base.js b/packages/eslint-config-hubspot/base.js index c4ebeb7e8f..9af22602e8 100644 --- a/packages/eslint-config-hubspot/base.js +++ b/packages/eslint-config-hubspot/base.js @@ -3,6 +3,5 @@ module.exports = { 'eslint-config-hubspot/legacy', 'eslint-config-hubspot/rules/es6', ], - parser: 'babel-eslint', rules: {} }; diff --git a/packages/eslint-config-hubspot/package.json b/packages/eslint-config-hubspot/package.json index 98e1f4ae8a..76bc4c925d 100644 --- a/packages/eslint-config-hubspot/package.json +++ b/packages/eslint-config-hubspot/package.json @@ -1,11 +1,11 @@ { "name": "eslint-config-hubspot", - "version": "1.0.5", + "version": "1.0.6", "description": "HubSpot's ESLint config, following our styleguide", "main": "index.js", "scripts": { "lint": "eslint .", - "test": "babel-tape-runner ./test/test-*.js" + "test": "babel-tape-runner ./test/test-*.js | faucet" }, "repository": { "type": "git", @@ -31,11 +31,14 @@ }, "homepage": "https://github.com/HubSpot/javascript", "devDependencies": { - "babel-eslint": "4.1.3", "babel-tape-runner": "1.2.0", - "eslint": "1.6.0", - "eslint-plugin-react": "3.5.1", - "react": "0.14.0", - "tape": "4.2.1" + "eslint": "^1.8.0", + "eslint-plugin-react": "^3.7.1", + "faucet": "0.0.1", + "react": "^0.13.3", + "tape": "^4.2.2" + }, + "peerDependencies": { + "eslint": ">=1.0.0" } } diff --git a/packages/eslint-config-hubspot/rules/es6.js b/packages/eslint-config-hubspot/rules/es6.js index b672d4aae1..b7fde7bf44 100644 --- a/packages/eslint-config-hubspot/rules/es6.js +++ b/packages/eslint-config-hubspot/rules/es6.js @@ -15,6 +15,7 @@ module.exports = { 'objectLiteralDuplicateProperties': false, 'objectLiteralShorthandMethods': true, 'objectLiteralShorthandProperties': true, + 'restParams': true, 'spread': true, 'superInFunctions': true, 'templateStrings': true, @@ -32,7 +33,7 @@ module.exports = { // disallow modifying variables of class declarations 'no-class-assign': 0, // disallow modifying variables that are declared using const - 'no-const-assign': 0, + '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 diff --git a/packages/eslint-config-hubspot/rules/react.js b/packages/eslint-config-hubspot/rules/react.js index f03854a055..589f7f0d3b 100644 --- a/packages/eslint-config-hubspot/rules/react.js +++ b/packages/eslint-config-hubspot/rules/react.js @@ -1,5 +1,4 @@ module.exports = { - 'parser': 'babel-eslint', 'plugins': [ 'react' ], @@ -10,17 +9,19 @@ module.exports = { // Prevent missing displayName in a React component definition 'react/display-name': 0, // Enforce boolean attributes notation in JSX - 'react/jsx-boolean-value': 0, + 'react/jsx-boolean-value': 2, // Enforce or disallow spaces inside of curly braces in JSX attributes 'react/jsx-curly-spacing': 0, // Prevent duplicate props in JSX 'react/jsx-no-duplicate-props': 0, // Disallow undeclared variables in JSX 'react/jsx-no-undef': 2, + // Enforce quote style for JSX attributes + 'react/jsx-quotes': 0, // Enforce propTypes declarations alphabetical sorting - 'react/jsx-sort-prop-types': 2, + 'react/jsx-sort-prop-types': 0, // Enforce props alphabetical sorting - 'react/jsx-sort-props': 2, + 'react/jsx-sort-props': 0, // Prevent React to be incorrectly marked as unused 'react/jsx-uses-react': 2, // Prevent variables used in JSX to be incorrectly marked as unused diff --git a/packages/eslint-config-hubspot/rules/style.js b/packages/eslint-config-hubspot/rules/style.js index 43bad28791..8518d496ac 100644 --- a/packages/eslint-config-hubspot/rules/style.js +++ b/packages/eslint-config-hubspot/rules/style.js @@ -21,7 +21,7 @@ module.exports = { // 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': [2, {'min': 2, 'properties': 'never', 'exceptions': ['e', 'i', 'Q', '$']}], + 'id-length': 0, // this option sets a specific tab width for your code 'indent': [2, 2], // specify whether double or single quotes should be used in JSX attributes @@ -49,9 +49,9 @@ module.exports = { // 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': 0, - // disallow multiple empty lines - 'no-multiple-empty-lines': [2, {'max': 2}], + '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 @@ -88,7 +88,7 @@ module.exports = { 'semi': [2, 'always'], // sort variables within the same declaration block 'sort-vars': 0, - // require a space after certain keywords + // require a space before certain keywords 'space-before-keywords': [2, 'always'], // require a space after certain keywords 'space-after-keywords': [2, 'always'], diff --git a/packages/eslint-config-hubspot/test/test-react-order.js b/packages/eslint-config-hubspot/test/test-react-order.js index 72e4ea9adf..a44c05c582 100644 --- a/packages/eslint-config-hubspot/test/test-react-order.js +++ b/packages/eslint-config-hubspot/test/test-react-order.js @@ -1,7 +1,6 @@ import test from 'tape'; import { CLIEngine } from 'eslint'; import eslintrc from '../'; -import baseConfig from '../base'; import reactRules from '../rules/react'; const cli = new CLIEngine({ @@ -21,42 +20,41 @@ function lint(text) { function wrapComponent(body) { return ` import React from 'react'; -export default class MyComponent extends React.Component { +export default React.createClass({ ${body} -} +}); `; } test('validate react prop order', t => { t.test('make sure our eslintrc has React linting dependencies', t => { - t.plan(2); - t.equal(baseConfig.parser, 'babel-eslint', 'uses babel-eslint'); + 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(` - displayName: '' - mixins: [] - propTypes: {} - contextTypes: {} - childContextTypes: {} - getDefaultProps() {} - getInitialState() {} - getChildContext() {} - componentWillMount() {} - componentDidMount() {} - componentWillReceiveProps() {} - shouldComponentUpdate() {} - componentWillUpdate() {} - componentDidUpdate() {} - componentWillUnmount() {} - setFoo() {} - getFoo() {} - setBar() {} - someMethod() {} - renderDogs() {} + displayName: '', + mixins: [], + propTypes: {}, + contextTypes: {}, + childContextTypes: {}, + getDefaultProps() {}, + getInitialState() {}, + getChildContext() {}, + componentWillMount() {}, + componentDidMount() {}, + componentWillReceiveProps() {}, + shouldComponentUpdate() {}, + componentWillUpdate() {}, + componentDidUpdate() {}, + componentWillUnmount() {}, + setFoo() {}, + getFoo() {}, + setBar() {}, + someMethod() {}, + renderDogs() {}, render() { return
; } `)); @@ -68,13 +66,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
; } `)); @@ -85,13 +83,13 @@ test('validate react prop order', t => { t.test('order: when random method after lifecycle methods', t => { t.plan(3); 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 31286cef4f..a05fd8dda4 100644 --- a/react/README.md +++ b/react/README.md @@ -194,42 +194,6 @@ ; ``` - - List __props__ in alphabetical order, unless you are spreading props and different ordering is required to maintain behavior. - - ```javascript - // bad - ; - - // good - ; - - // meh (introducing spread changes behavior, so do what you must...) - ; - ``` - - - - List __propTypes__ alphabetically - - ```javascript - // bad - var Component = React.createClass({ - propTypes: { - z: React.PropTypes.number, - a: React.PropTypes.any, - b: React.PropTypes.string - } - }); - - // good - var Component = React.createClass({ - propTypes: { - a: React.PropTypes.any, - b: React.PropTypes.string, - z: React.PropTypes.number - } - }); - ``` - - Declare every prop in `propTypes`. If you use a value on `this.props` anywhere in your component, it should be listed in `propTypes`. ```javascript From d94422218a1edae82132a30e39c2ea1440f85716 Mon Sep 17 00:00:00 2001 From: Nick Hwang Date: Mon, 30 Nov 2015 18:21:20 -0500 Subject: [PATCH 15/54] Add experimentalObjectRestSpread --- packages/eslint-config-hubspot/package.json | 4 ++-- packages/eslint-config-hubspot/rules/es6.js | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/eslint-config-hubspot/package.json b/packages/eslint-config-hubspot/package.json index 76bc4c925d..3d1eebc7e1 100644 --- a/packages/eslint-config-hubspot/package.json +++ b/packages/eslint-config-hubspot/package.json @@ -32,8 +32,8 @@ "homepage": "https://github.com/HubSpot/javascript", "devDependencies": { "babel-tape-runner": "1.2.0", - "eslint": "^1.8.0", - "eslint-plugin-react": "^3.7.1", + "eslint": "^1.10.2", + "eslint-plugin-react": "^3.11.1", "faucet": "0.0.1", "react": "^0.13.3", "tape": "^4.2.2" diff --git a/packages/eslint-config-hubspot/rules/es6.js b/packages/eslint-config-hubspot/rules/es6.js index b7fde7bf44..1509ad9424 100644 --- a/packages/eslint-config-hubspot/rules/es6.js +++ b/packages/eslint-config-hubspot/rules/es6.js @@ -19,7 +19,8 @@ module.exports = { 'spread': true, 'superInFunctions': true, 'templateStrings': true, - 'jsx': true + 'jsx': true, + 'experimentalObjectRestSpread': true }, 'rules': { // require parens in arrow function arguments From cfbf2f16bca2f590e791ef8080b31cb7152c3ef6 Mon Sep 17 00:00:00 2001 From: Nick Hwang Date: Sat, 5 Dec 2015 22:33:36 -0500 Subject: [PATCH 16/54] Minor fix in jsx boolean rule --- package.json | 2 +- packages/eslint-config-hubspot/package.json | 2 +- packages/eslint-config-hubspot/rules/react.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 7b70ef2948..675daaeffc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hubspot-style", - "version": "1.0.6", + "version": "1.0.7", "description": "HubSpot's version of a mostly reasonable approach to JavaScript", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", diff --git a/packages/eslint-config-hubspot/package.json b/packages/eslint-config-hubspot/package.json index 3d1eebc7e1..d00807ab9a 100644 --- a/packages/eslint-config-hubspot/package.json +++ b/packages/eslint-config-hubspot/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-hubspot", - "version": "1.0.6", + "version": "1.0.7", "description": "HubSpot's ESLint config, following our styleguide", "main": "index.js", "scripts": { diff --git a/packages/eslint-config-hubspot/rules/react.js b/packages/eslint-config-hubspot/rules/react.js index 589f7f0d3b..5ac5380513 100644 --- a/packages/eslint-config-hubspot/rules/react.js +++ b/packages/eslint-config-hubspot/rules/react.js @@ -9,7 +9,7 @@ module.exports = { // Prevent missing displayName in a React component definition 'react/display-name': 0, // Enforce boolean attributes notation in JSX - 'react/jsx-boolean-value': 2, + 'react/jsx-boolean-value': [2, 'always'], // Enforce or disallow spaces inside of curly braces in JSX attributes 'react/jsx-curly-spacing': 0, // Prevent duplicate props in JSX From c6f8670c94553b1a93002dc3c0da2c6a2074c7ae Mon Sep 17 00:00:00 2001 From: Nick Hwang Date: Tue, 15 Dec 2015 18:52:22 -0500 Subject: [PATCH 17/54] Update README --- README.md | 120 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 114 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index a8cae50e14..9cc4ef6529 100644 --- a/README.md +++ b/README.md @@ -96,6 +96,8 @@ Other Style Guides (from Airbnb) > 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 var a = 1; @@ -110,6 +112,8 @@ Other Style Guides (from Airbnb) > 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 var count = 1; @@ -142,6 +146,8 @@ Other Style Guides (from Airbnb) - [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(); @@ -214,6 +220,8 @@ Other Style Guides (from Airbnb) - [3.5](#3.5) Use object method shorthand. + eslint rules: [`object-shorthand`](http://eslint.org/docs/rules/object-shorthand.html). + ```javascript // bad const atom = { @@ -239,6 +247,8 @@ Other Style Guides (from Airbnb) > 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'; @@ -288,6 +298,8 @@ Other Style Guides (from Airbnb) - [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(); @@ -404,6 +416,8 @@ Other Style Guides (from Airbnb) - [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"; @@ -436,6 +450,8 @@ Other Style Guides (from Airbnb) > 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 function sayHi(name) { @@ -613,6 +629,8 @@ Other Style Guides (from Airbnb) > 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 [1, 2, 3].map(function (x) { @@ -633,6 +651,8 @@ Other Style Guides (from Airbnb) > 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 [1, 2, 3].map(number => `A string containing the ${number}.`); @@ -673,6 +693,8 @@ Other Style Guides (from Airbnb) > Why? Less visual clutter. + eslint rules: [`arrow-parens`](http://eslint.org/docs/rules/arrow-parens.html). + ```js // good [1, 2, 3].map(x => x * x); @@ -851,6 +873,8 @@ Other Style Guides (from Airbnb) > 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]; @@ -883,6 +907,8 @@ Other Style Guides (from Airbnb) - [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, @@ -930,6 +956,8 @@ Other Style Guides (from Airbnb) > 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(), @@ -1124,12 +1152,14 @@ Other Style Guides (from Airbnb) - [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: - + **Objects** evaluate to **true** - + **Undefined** evaluates to **false** - + **Null** evaluates to **false** - + **Booleans** evaluate to **the value of the boolean** - + **Numbers** evaluate to **false** if **+0, -0, or NaN**, otherwise **true** - + **Strings** evaluate to **false** if an empty string `''`, otherwise **true** + eslint rules: [`eqeqeq`](http://eslint.org/docs/rules/eqeqeq.html). + + + **Objects** evaluate to **true** + + **Undefined** evaluates to **false** + + **Null** evaluates to **false** + + **Booleans** evaluate to **the value of the boolean** + + **Numbers** evaluate to **false** if **+0, -0, or NaN**, otherwise **true** + + **Strings** evaluate to **false** if an empty string `''`, otherwise **true** ```javascript if ([0]) { @@ -1196,6 +1226,8 @@ Other Style Guides (from Airbnb) - [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) { @@ -1326,6 +1358,8 @@ Other Style Guides (from Airbnb) - [18.1](#18.1) Use soft tabs set to 2 spaces. + eslint rules: [`indent`](http://eslint.org/docs/rules/indent.html). + ```javascript // bad function() { @@ -1345,6 +1379,8 @@ Other Style Guides (from Airbnb) - [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(){ @@ -1371,6 +1407,8 @@ Other Style Guides (from Airbnb) - [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. + 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 if(isJedi) { @@ -1395,6 +1433,8 @@ Other Style Guides (from Airbnb) - [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; @@ -1526,6 +1566,8 @@ Other Style Guides (from Airbnb) - [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() { @@ -1556,6 +1598,57 @@ Other Style Guides (from Airbnb) } ``` + - [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' }; + ``` **[⬆ back to top](#table-of-contents)** @@ -1563,6 +1656,8 @@ Other Style Guides (from Airbnb) - [19.1](#19.1) Leading commas: **Nope.** + eslint rules: [`comma-style`](http://eslint.org/docs/rules/comma-style.html). + ```javascript // bad const story = [ @@ -1597,6 +1692,8 @@ Other Style Guides (from Airbnb) - [19.2](#19.2) Additional trailing comma: **Yup.** + eslint rules: [`no-comma-dangle`](http://eslint.org/docs/rules/no-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 @@ -1645,6 +1742,8 @@ Other Style Guides (from Airbnb) - [20.1](#20.1) **Yup.** + eslint rules: [`semi`](http://eslint.org/docs/rules/semi.html). + ```javascript // bad (function() { @@ -1765,6 +1864,8 @@ Other Style Guides (from Airbnb) - [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 = {}; @@ -1802,6 +1903,8 @@ Other Style Guides (from Airbnb) - [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'; @@ -1839,6 +1942,7 @@ Other Style Guides (from Airbnb) ``` - [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 { @@ -2250,6 +2354,7 @@ Other Style Guides (from Airbnb) - **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-style-guide) - **Compass Learning**: [compasslearning/javascript-style-guide](https://github.com/compasslearning/javascript-style-guide) @@ -2271,6 +2376,7 @@ Other Style Guides (from Airbnb) - **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-style-guide) - **Mighty Spring**: [mightyspring/javascript](https://github.com/mightyspring/javascript) @@ -2283,9 +2389,11 @@ Other Style Guides (from Airbnb) - **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) From 492cab8696d6be6b8a6c5ec49bd483e84dfa78cd Mon Sep 17 00:00:00 2001 From: Nick Hwang Date: Tue, 15 Dec 2015 21:24:34 -0500 Subject: [PATCH 18/54] Update react/README --- react/README.md | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/react/README.md b/react/README.md index a05fd8dda4..b177af82ce 100644 --- a/react/README.md +++ b/react/README.md @@ -33,6 +33,8 @@ - Use class extends React.Component unless you have a very good reason to use mixins. + 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({ @@ -54,7 +56,10 @@ - **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'); @@ -101,6 +106,8 @@ ## 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 @@ -297,6 +306,9 @@ ## 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 @@ -306,6 +318,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 Date: Tue, 15 Dec 2015 22:22:54 -0500 Subject: [PATCH 19/54] Update eslint plugin --- packages/eslint-config-hubspot/CHANGELOG.md | 63 +++++++++++++++++++ packages/eslint-config-hubspot/README.md | 42 ------------- packages/eslint-config-hubspot/base.js | 2 +- packages/eslint-config-hubspot/index.js | 2 +- packages/eslint-config-hubspot/legacy.js | 2 +- packages/eslint-config-hubspot/package.json | 6 +- packages/eslint-config-hubspot/rules/es6.js | 6 +- packages/eslint-config-hubspot/rules/react.js | 36 +++++++++-- packages/eslint-config-hubspot/rules/style.js | 11 ++-- 9 files changed, 112 insertions(+), 58 deletions(-) create mode 100644 packages/eslint-config-hubspot/CHANGELOG.md diff --git a/packages/eslint-config-hubspot/CHANGELOG.md b/packages/eslint-config-hubspot/CHANGELOG.md new file mode 100644 index 0000000000..bc269e9222 --- /dev/null +++ b/packages/eslint-config-hubspot/CHANGELOG.md @@ -0,0 +1,63 @@ +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-hubspot/README.md b/packages/eslint-config-hubspot/README.md index 4c2316f3f7..181b8ce34f 100644 --- a/packages/eslint-config-hubspot/README.md +++ b/packages/eslint-config-hubspot/README.md @@ -46,45 +46,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 - -### 1.0.2 -- enable rest params in linter, derp. (#592) -- enforce rule 18.5, ensuring files end with a single newline character. (#578) - -### 1.0.1 - -oops - -### 1.0.0 -- require `eslint` `v1.0.0` or higher -- removes `babel-eslint` dependency - -### 0.1.1 -- 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 - -- 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] - -[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 - -### 0.0.9 - -- add rule no-undef -- add rule id-length - -### 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-hubspot/base.js b/packages/eslint-config-hubspot/base.js index 9af22602e8..0dc72dfe10 100644 --- a/packages/eslint-config-hubspot/base.js +++ b/packages/eslint-config-hubspot/base.js @@ -2,6 +2,6 @@ module.exports = { extends: [ 'eslint-config-hubspot/legacy', 'eslint-config-hubspot/rules/es6', - ], + ].map(require.resolve), rules: {} }; diff --git a/packages/eslint-config-hubspot/index.js b/packages/eslint-config-hubspot/index.js index a89c69aab8..fc0dcf2d07 100644 --- a/packages/eslint-config-hubspot/index.js +++ b/packages/eslint-config-hubspot/index.js @@ -2,6 +2,6 @@ module.exports = { extends: [ 'eslint-config-hubspot/base', 'eslint-config-hubspot/rules/react', - ], + ].map(require.resolve), rules: {} }; diff --git a/packages/eslint-config-hubspot/legacy.js b/packages/eslint-config-hubspot/legacy.js index 8992fcd2df..08c5661fa5 100644 --- a/packages/eslint-config-hubspot/legacy.js +++ b/packages/eslint-config-hubspot/legacy.js @@ -7,7 +7,7 @@ module.exports = { 'eslint-config-hubspot/rules/strict', 'eslint-config-hubspot/rules/style', 'eslint-config-hubspot/rules/variables' - ], + ].map(require.resolve), env: { browser: true, node: true, diff --git a/packages/eslint-config-hubspot/package.json b/packages/eslint-config-hubspot/package.json index d00807ab9a..182c47db1f 100644 --- a/packages/eslint-config-hubspot/package.json +++ b/packages/eslint-config-hubspot/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-hubspot", - "version": "1.0.7", + "version": "2.0.0", "description": "HubSpot's ESLint config, following our styleguide", "main": "index.js", "scripts": { @@ -32,8 +32,8 @@ "homepage": "https://github.com/HubSpot/javascript", "devDependencies": { "babel-tape-runner": "1.2.0", - "eslint": "^1.10.2", - "eslint-plugin-react": "^3.11.1", + "eslint": "^1.10.3", + "eslint-plugin-react": "^3.11.3", "faucet": "0.0.1", "react": "^0.13.3", "tape": "^4.2.2" diff --git a/packages/eslint-config-hubspot/rules/es6.js b/packages/eslint-config-hubspot/rules/es6.js index 1509ad9424..35d190d36b 100644 --- a/packages/eslint-config-hubspot/rules/es6.js +++ b/packages/eslint-config-hubspot/rules/es6.js @@ -26,7 +26,8 @@ module.exports = { // require parens in arrow function arguments 'arrow-parens': 0, // require space before/after arrow function's arrow - 'arrow-spacing': 0, + // 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 @@ -40,7 +41,8 @@ module.exports = { // require let or const instead of var 'no-var': 2, // require method and property shorthand syntax for object literals - 'object-shorthand': 0, + // 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() diff --git a/packages/eslint-config-hubspot/rules/react.js b/packages/eslint-config-hubspot/rules/react.js index 5ac5380513..4d41cdb006 100644 --- a/packages/eslint-config-hubspot/rules/react.js +++ b/packages/eslint-config-hubspot/rules/react.js @@ -7,44 +7,67 @@ 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, // 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, 'always'], + // 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, {'selfClosing': 'tag-aligned', 'nonEmpty': 'after-props'}], // 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, + // 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], // 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, // 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 quote style for JSX attributes - 'react/jsx-quotes': 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, // Enforce props alphabetical sorting + // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-sort-props.md 'react/jsx-sort-props': 0, // 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, // 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 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 - '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-did-update-set-state': [2, 'allow-in-func'], // 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, // 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, // 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, // 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, // 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', @@ -75,6 +98,11 @@ module.exports = { } }], // Prevent missing parentheses around multilines JSX - 'react/wrap-multilines': 2 + // 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-hubspot/rules/style.js b/packages/eslint-config-hubspot/rules/style.js index 8518d496ac..4ad35174d6 100644 --- a/packages/eslint-config-hubspot/rules/style.js +++ b/packages/eslint-config-hubspot/rules/style.js @@ -1,7 +1,7 @@ module.exports = { 'rules': { // enforce spacing inside array brackets - 'array-bracket-spacing': 0, + 'array-bracket-spacing': [2, 'never'], // enforce one true brace style 'brace-style': [2, '1tbs', {'allowSingleLine': true }], // require camel case names @@ -11,7 +11,7 @@ module.exports = { // enforce one true comma style 'comma-style': [2, 'last'], // require or disallow padding inside computed properties - 'computed-property-spacing': 0, + '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 @@ -23,8 +23,10 @@ module.exports = { // 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 - 'indent': [2, 2], + // 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}], @@ -95,9 +97,10 @@ module.exports = { // 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, 'never'], // require or disallow spaces inside parentheses - 'space-in-parens': 0, + 'space-in-parens': [2, 'never'], // require spaces around operators 'space-infix-ops': 2, // require a space after return, throw, and case From eef1a579c047f1e8a5fae811a3d1a0bf03eaaf3e Mon Sep 17 00:00:00 2001 From: Nick Hwang Date: Tue, 15 Dec 2015 22:23:28 -0500 Subject: [PATCH 20/54] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 675daaeffc..c0dc84ed8b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hubspot-style", - "version": "1.0.7", + "version": "2.0.0", "description": "HubSpot's version of a mostly reasonable approach to JavaScript", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", From 5a87db2c9423c9efe03b526d719e4204f7fbb645 Mon Sep 17 00:00:00 2001 From: Nick Hwang Date: Wed, 30 Dec 2015 16:34:47 -0500 Subject: [PATCH 21/54] Add tools for easier updating with airbnb/master --- bin/cleanup | 23 +++++++++++++++++++ bin/constants | 13 +++++++++++ bin/difftool | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++ package.json | 6 +++-- 4 files changed, 101 insertions(+), 2 deletions(-) create mode 100755 bin/cleanup create mode 100755 bin/constants create mode 100755 bin/difftool diff --git a/bin/cleanup b/bin/cleanup new file mode 100755 index 0000000000..e27f8c7609 --- /dev/null +++ b/bin/cleanup @@ -0,0 +1,23 @@ +#!/usr/bin/env bash + +# Go to project git root +PROJECT_ROOT=$(git rev-parse --show-toplevel) +cd $PROJECT_ROOT + +# Load constants +source bin/constants + +# Remove remote +if [[ ! -z "$AIRBNB_REMOTE" ]]; then + git remote remove "$AIRBNB_REMOTE" +fi + +# Remove compare branch +if [[ ! -z $(git branch | grep "$COMPARATE_BRANCH") ]]; then + git branch -D "$COMPARATE_BRANCH" +fi + +# Remove working branch +if [[ ! -z $(git branch | grep "$WORKING_BRANCH") ]]; then + git branch -D "$WORKING_BRANCH" +fi diff --git a/bin/constants b/bin/constants new file mode 100755 index 0000000000..bae57d6d0e --- /dev/null +++ b/bin/constants @@ -0,0 +1,13 @@ +#!/usr/bin/env bash + +# Constants +AIRBNB_GIT="git@github.com:airbnb/javascript.git" +AIRBNB_REMOTE="__airbnb__" +REMOTE_BRANCH="master" +COMPARATE_BRANCH="__compare-branch__" +WORKING_BRANCH="__airbnb-updates__" +ESLINT_AIRBNB="packages/eslint-config-airbnb" +ESLINT_HUBSPOT="packages/eslint-config-hubspot" +STASH_MESSAGE="[Diff] Pre-diff stash" +COMMIT_MESSAGE="Renamed eslint-config-airbnb -> elsint-config-hubspot" +CURRENT_BRANCH=$(git branch | grep '*' | cut -d' ' -f2) diff --git a/bin/difftool b/bin/difftool new file mode 100755 index 0000000000..22b6dd7767 --- /dev/null +++ b/bin/difftool @@ -0,0 +1,61 @@ +#!/usr/bin/env bash + +# Go to project git root +PROJECT_ROOT=$(git rev-parse --show-toplevel) +cd $PROJECT_ROOT + +# Load constants +source bin/constants + +# Helpers +function checkout() { + local EXISTS=$(git branch | grep "$1") + + if [[ ! -z "$2" ]]; then + if [[ ! -z "$EXISTS" ]];then + git branch -D $1 + fi + git checkout -b "$1" "$2" + else + if [[ -z "$EXISTS" ]];then + git checkout -b "$1" + else + git checkout "$1" + fi + fi +} + +function rename() { + rm -rf "$1" + mv "$2" "$1" +} + +# Add Airbnb git remote +if [[ -z $(git remote -v | grep "$AIRBNB_REMOTE $AIRBNB_GIT (fetch)") ]]; then + git remote add "$AIRBNB_REMOTE" "$AIRBNB_GIT" +fi + +# Stash any existing changes before diffing +git stash save "$STASH_MESSAGE" + +# Checkout working branch +checkout "$WORKING_BRANCH" + +# Fetch Airbnb changes +git fetch "$AIRBNB_REMOTE" "$REMOTE_BRANCH" + +# Checkout Airbnb remote branch +checkout "$COMPARATE_BRANCH" "$AIRBNB_REMOTE/$REMOTE_BRANCH" + +# Rename eslint-config-airbnb to eslint-config-hubspot for diffing +rename "$ESLINT_HUBSPOT" "$ESLINT_AIRBNB" + +# Commit rename for diffing +git add "$ESLINT_AIRBNB" "$ESLINT_HUBSPOT" +git commit -m "$COMMIT_MESSAGE" + +# Checkout last branch to begin diffing +git checkout "$WORKING_BRANCH" + +# Begin diffing +git difftool --prompt "$COMPARATE_BRANCH" diff --git a/package.json b/package.json index c0dc84ed8b..b3be894660 100644 --- a/package.json +++ b/package.json @@ -3,8 +3,10 @@ "version": "2.0.0", "description": "HubSpot's version of a mostly reasonable approach to JavaScript", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1", - "publish-all": "npm publish && cd ./packages/eslint-config-hubspot && npm publish" + "update": "./bin/difftool", + "cleanup ": "./bin/cleanup", + "publish:config": "cd packages/eslint-config-hubspot && npm publish", + "publish:all": "npm publish && npm run publish:config" }, "repository": { "type": "git", From 0c1a20a6c61e70ab0bf0e54f08b020e0fc0cb192 Mon Sep 17 00:00:00 2001 From: Nick Hwang Date: Wed, 30 Dec 2015 18:07:10 -0500 Subject: [PATCH 22/54] Rebase with airbnb/master --- README.md | 335 ++++++++++++------ linters/{jshintrc => .jshintrc} | 4 +- package.json | 2 +- packages/eslint-config-hubspot/index.js | 3 +- packages/eslint-config-hubspot/legacy.js | 1 - packages/eslint-config-hubspot/package.json | 4 +- .../rules/best-practices.js | 4 +- .../eslint-config-hubspot/rules/legacy.js | 2 - packages/eslint-config-hubspot/rules/react.js | 68 +++- packages/eslint-config-hubspot/rules/style.js | 20 +- react/README.md | 328 ++++++++++------- 11 files changed, 494 insertions(+), 277 deletions(-) rename linters/{jshintrc => .jshintrc} (95%) diff --git a/README.md b/README.md index 9cc4ef6529..0ce0d3a63d 100644 --- a/README.md +++ b/README.md @@ -94,9 +94,9 @@ Other Style Guides (from Airbnb) - [2.1](#2.1) Use `const` for all of your references; avoid using `var`. - > Why? This ensures that you can't reassign your references, 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). + 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 @@ -110,9 +110,9 @@ Other Style Guides (from Airbnb) - [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). + eslint rules: [`no-var`](http://eslint.org/docs/rules/no-var.html). ```javascript // bad @@ -146,7 +146,7 @@ Other Style Guides (from Airbnb) - [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). + eslint rules: [`no-new-object`](http://eslint.org/docs/rules/no-new-object.html). ```javascript // bad @@ -194,7 +194,7 @@ Other Style Guides (from Airbnb) - [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 @@ -220,7 +220,7 @@ Other Style Guides (from Airbnb) - [3.5](#3.5) Use object method shorthand. - eslint rules: [`object-shorthand`](http://eslint.org/docs/rules/object-shorthand.html). + eslint rules: [`object-shorthand`](http://eslint.org/docs/rules/object-shorthand.html). ```javascript // bad @@ -245,9 +245,9 @@ Other Style Guides (from Airbnb) - [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). + eslint rules: [`object-shorthand`](http://eslint.org/docs/rules/object-shorthand.html). ```javascript const lukeSkywalker = 'Luke Skywalker'; @@ -265,7 +265,7 @@ Other Style Guides (from Airbnb) - [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'; @@ -298,7 +298,7 @@ Other Style Guides (from Airbnb) - [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). + eslint rules: [`no-array-constructor`](http://eslint.org/docs/rules/no-array-constructor.html). ```javascript // bad @@ -349,7 +349,7 @@ Other Style Guides (from Airbnb) - [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 @@ -387,7 +387,7 @@ Other Style Guides (from Airbnb) - [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 @@ -416,7 +416,7 @@ Other Style Guides (from Airbnb) - [6.1](#6.1) Use single quotes `''` for strings. - eslint rules: [`quotes`](http://eslint.org/docs/rules/quotes.html). + eslint rules: [`quotes`](http://eslint.org/docs/rules/quotes.html). ```javascript // bad @@ -426,7 +426,7 @@ Other Style Guides (from Airbnb) 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 @@ -448,9 +448,9 @@ Other Style Guides (from Airbnb) - [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). + eslint rules: [`prefer-template`](http://eslint.org/docs/rules/prefer-template.html). ```javascript // bad @@ -477,7 +477,7 @@ Other Style Guides (from Airbnb) - [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 @@ -499,6 +499,7 @@ Other Style Guides (from Airbnb) ``` - [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 @@ -535,7 +536,7 @@ Other Style Guides (from Airbnb) - [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 @@ -579,19 +580,19 @@ Other Style Guides (from Airbnb) - [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. @@ -607,17 +608,75 @@ Other Style Guides (from Airbnb) } ``` -- [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. + + ```javascript + // bad + var add = new 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; + } - > Why? Creating a function in this way evaluates a string similarly to eval(), which opens vulnerabilities. + function f2(a) { + if (!a) { a = 1; } + } - ```javascript - // bad - var add = new Function('a', 'b', 'return a + b'); + // good + function f3(a) { + const b = a || 1; + } - // still bad - var subtract = Function('a', 'b', 'return a - b'); - ``` + function f4(a = 1) { + } + ``` **[⬆ back to top](#table-of-contents)** @@ -625,11 +684,11 @@ Other Style Guides (from Airbnb) - [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). + 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 @@ -647,11 +706,11 @@ Other Style Guides (from Airbnb) - [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. - > 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). + 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 @@ -672,7 +731,7 @@ Other Style Guides (from Airbnb) - [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 @@ -691,9 +750,9 @@ Other Style Guides (from Airbnb) - [8.4](#8.4) If your function only takes a single argument, feel free to omit the parentheses. - > Why? Less visual clutter. + > Why? Less visual clutter. - eslint rules: [`arrow-parens`](http://eslint.org/docs/rules/arrow-parens.html). + eslint rules: [`arrow-parens`](http://eslint.org/docs/rules/arrow-parens.html). ```js // good @@ -710,14 +769,14 @@ Other Style Guides (from Airbnb) - [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; @@ -739,7 +798,7 @@ Other Style Guides (from Airbnb) - [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 @@ -748,7 +807,7 @@ Other Style Guides (from Airbnb) Queue.apply(this, contents); } inherits(PeekableQueue, Queue); - PeekableQueue.prototype.peek = function() { + PeekableQueue.prototype.peek = function () { return this._queue[0]; } @@ -764,12 +823,12 @@ Other Style Guides (from Airbnb) ```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; }; @@ -822,7 +881,7 @@ Other Style Guides (from Airbnb) - [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 @@ -840,7 +899,7 @@ Other Style Guides (from Airbnb) - [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 @@ -852,7 +911,7 @@ Other Style Guides (from Airbnb) - [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 @@ -871,9 +930,9 @@ Other Style Guides (from Airbnb) - [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). + eslint rules: [`no-iterator`](http://eslint.org/docs/rules/no-iterator.html). ```javascript const numbers = [1, 2, 3, 4, 5]; @@ -898,7 +957,7 @@ Other Style Guides (from Airbnb) - [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)** @@ -907,7 +966,7 @@ Other Style Guides (from Airbnb) - [12.1](#12.1) Use dot notation when accessing properties. - eslint rules: [`dot-notation`](http://eslint.org/docs/rules/dot-notation.html). + eslint rules: [`dot-notation`](http://eslint.org/docs/rules/dot-notation.html). ```javascript const luke = { @@ -956,7 +1015,7 @@ Other Style Guides (from Airbnb) > 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). + eslint rules: [`one-var`](http://eslint.org/docs/rules/one-var.html). ```javascript // bad @@ -978,7 +1037,7 @@ Other Style Guides (from Airbnb) - [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 @@ -1003,11 +1062,11 @@ Other Style Guides (from Airbnb) - [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..'); @@ -1023,7 +1082,7 @@ Other Style Guides (from Airbnb) } // bad - unnecessary function call - function(hasName) { + function (hasName) { const name = getName(); if (!hasName) { @@ -1036,7 +1095,7 @@ Other Style Guides (from Airbnb) } // good - function(hasName) { + function (hasName) { if (!hasName) { return false; } @@ -1096,7 +1155,7 @@ Other Style Guides (from Airbnb) anonymous(); // => TypeError anonymous is not a function - var anonymous = function() { + var anonymous = function () { console.log('anonymous function expression'); }; } @@ -1150,16 +1209,17 @@ Other Style Guides (from Airbnb) ## 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). + eslint rules: [`eqeqeq`](http://eslint.org/docs/rules/eqeqeq.html). - + **Objects** evaluate to **true** - + **Undefined** evaluates to **false** - + **Null** evaluates to **false** - + **Booleans** evaluate to **the value of the boolean** - + **Numbers** evaluate to **false** if **+0, -0, or NaN**, otherwise **true** - + **Strings** evaluate to **false** if an empty string `''`, otherwise **true** + + **Objects** evaluate to **true** + + **Undefined** evaluates to **false** + + **Null** evaluates to **false** + + **Booleans** evaluate to **the value of the boolean** + + **Numbers** evaluate to **false** if **+0, -0, or NaN**, otherwise **true** + + **Strings** evaluate to **false** if an empty string `''`, otherwise **true** ```javascript if ([0]) { @@ -1215,10 +1275,10 @@ Other Style Guides (from Airbnb) } // bad - function() { return false; } + function () { return false; } // good - function() { + function () { return false; } ``` @@ -1358,28 +1418,28 @@ Other Style Guides (from Airbnb) - [18.1](#18.1) Use soft tabs set to 2 spaces. - eslint rules: [`indent`](http://eslint.org/docs/rules/indent.html). + 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). + eslint rules: [`space-before-blocks`](http://eslint.org/docs/rules/space-before-blocks.html). ```javascript // bad @@ -1407,7 +1467,7 @@ Other Style Guides (from Airbnb) - [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. - 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). + 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 @@ -1433,7 +1493,7 @@ Other Style Guides (from Airbnb) - [18.4](#18.4) Set off operators with spaces. - eslint rules: [`space-infix-ops`](http://eslint.org/docs/rules/space-infix-ops.html). + eslint rules: [`space-infix-ops`](http://eslint.org/docs/rules/space-infix-ops.html). ```javascript // bad @@ -1447,14 +1507,14 @@ Other Style Guides (from Airbnb) ```javascript // bad - (function(global) { + (function (global) { // ...stuff... })(this); ``` ```javascript // bad - (function(global) { + (function (global) { // ...stuff... })(this);↵ ↵ @@ -1462,7 +1522,7 @@ Other Style Guides (from Airbnb) ```javascript // good - (function(global) { + (function (global) { // ...stuff... })(this);↵ ``` @@ -1566,7 +1626,7 @@ Other Style Guides (from Airbnb) - [18.8](#18.8) Do not pad your blocks with blank lines. - eslint rules: [`padded-blocks`](http://eslint.org/docs/rules/padded-blocks.html). + eslint rules: [`padded-blocks`](http://eslint.org/docs/rules/padded-blocks.html). ```javascript // bad @@ -1600,7 +1660,7 @@ Other Style Guides (from Airbnb) - [18.9](#18.9) Do not add spaces inside parentheses. - eslint rules: [`space-in-parens`](http://eslint.org/docs/rules/space-in-parens.html). + eslint rules: [`space-in-parens`](http://eslint.org/docs/rules/space-in-parens.html). ```javascript // bad @@ -1626,7 +1686,7 @@ Other Style Guides (from Airbnb) - [18.10](#18.10) Do not add spaces inside brackets. - eslint rules: [`array-bracket-spacing`](http://eslint.org/docs/rules/array-bracket-spacing.html). + eslint rules: [`array-bracket-spacing`](http://eslint.org/docs/rules/array-bracket-spacing.html). ```javascript // bad @@ -1640,7 +1700,7 @@ Other Style Guides (from Airbnb) - [18.11](#18.11) Add spaces inside curly braces. - eslint rules: [`object-curly-spacing`](http://eslint.org/docs/rules/object-curly-spacing.html). + eslint rules: [`object-curly-spacing`](http://eslint.org/docs/rules/object-curly-spacing.html). ```javascript // bad @@ -1650,13 +1710,40 @@ Other Style Guides (from Airbnb) 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)** ## Commas - [19.1](#19.1) Leading commas: **Nope.** - eslint rules: [`comma-style`](http://eslint.org/docs/rules/comma-style.html). + eslint rules: [`comma-style`](http://eslint.org/docs/rules/comma-style.html). ```javascript // bad @@ -1692,9 +1779,9 @@ Other Style Guides (from Airbnb) - [19.2](#19.2) Additional trailing comma: **Yup.** - eslint rules: [`no-comma-dangle`](http://eslint.org/docs/rules/no-comma-dangle.html). + eslint rules: [`no-comma-dangle`](http://eslint.org/docs/rules/no-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. + > 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 @@ -1742,11 +1829,11 @@ Other Style Guides (from Airbnb) - [20.1](#20.1) **Yup.** - eslint rules: [`semi`](http://eslint.org/docs/rules/semi.html). + eslint rules: [`semi`](http://eslint.org/docs/rules/semi.html). ```javascript // bad - (function() { + (function () { const name = 'Skywalker' return name })() @@ -1864,7 +1951,7 @@ Other Style Guides (from Airbnb) - [22.2](#22.2) Use camelCase when naming objects, functions, and instances. - eslint rules: [`camelcase`](http://eslint.org/docs/rules/camelcase.html). + eslint rules: [`camelcase`](http://eslint.org/docs/rules/camelcase.html). ```javascript // bad @@ -1903,7 +1990,7 @@ Other Style Guides (from Airbnb) - [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). + eslint rules: [`no-underscore-dangle`](http://eslint.org/docs/rules/no-underscore-dangle.html). ```javascript // bad @@ -1920,7 +2007,7 @@ Other Style Guides (from Airbnb) // bad function foo() { const self = this; - return function() { + return function () { console.log(self); }; } @@ -1928,7 +2015,7 @@ Other Style Guides (from Airbnb) // bad function foo() { const that = this; - return function() { + return function () { console.log(that); }; } @@ -2050,7 +2137,7 @@ Other Style Guides (from Airbnb) ... - $(this).on('listingUpdated', function(e, listingId) { + $(this).on('listingUpdated', function (e, listingId) { // do something with listingId }); ``` @@ -2063,7 +2150,7 @@ Other Style Guides (from Airbnb) ... - $(this).on('listingUpdated', function(e, data) { + $(this).on('listingUpdated', function (e, data) { // do something with data.listingId }); ``` @@ -2164,10 +2251,10 @@ Other Style Guides (from Airbnb) ## Testing - - [28.1](#28.1) **Yup.** + - [28.1](#28.1) **Yup.** ```javascript - function() { + function () { return true; } ``` @@ -2213,35 +2300,46 @@ Other Style Guides (from Airbnb) ]; ``` + - [29.2](#29.2) Addendum to [using PascalCase](#22.2). Constructors require a capital letters, but functions can be capitalize too. The main reason for the latter is for libraries like `Immutable` which allow (and encourage?) initializing objects without `new` + + + ```javascript + // okay + const mapInstance = new Map(); + + // okay + const mapInstance = Map(); + ``` - - [29.2](#29.2) Variable names should be at least 2 characters long, except `e`, `i`, `Q`, and `$` which are commonly used for event, loop index, Q promise, and jQuery (respectively) + - [29.3](#29.3) Addendum to [add spaces inside curly braces](#18.11). Some prefer spacing, others don't. If you do use spacing, make sure there is a leading and trailing space and at most one space. ```javascript // bad - const n = 24; + const greetings = {hello: 'world' }; + const greetings = { hello: 'world'}; - // good - const theAnswer = 24; + // bad + const greetings = { hello: 'world' }; // okay - const e = event; - e.preventDefault(); + const greetings = {hello: 'world'}; // okay - for (let i = 0; i < 24; ++i) { - magic(i); - } + const greetings = { hello: 'world' }; ``` - - [29.3](#29.3) Addendum to [using PascalCase](#22.3). Constructors require a capital letters, but functions can be capitalize too. The main reason for the latter is for libraries like `Immutable` which allow (and encourage?) initializing objects without `new` - + - [29.4](#29.4) Addendum to [spacing in a function signature](#7.11). Some prefer the leading space, others don't in anonymous functions. Just be consistent and use, at most, one space. However, do omit the space for named functions. ```javascript - // okay - const mapInstance = new Map(); + // bad + const f = function(){}; + const g = function (){}; + const h = function a (){}; // okay - const mapInstance = Map(); + const z = function() {}; + const y = function () {}; + const z = function b() {}; ``` @@ -2362,6 +2460,7 @@ Other Style Guides (from Airbnb) - **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) 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/package.json b/package.json index b3be894660..4799579699 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hubspot-style", - "version": "2.0.0", + "version": "2.1.0", "description": "HubSpot's version of a mostly reasonable approach to JavaScript", "scripts": { "update": "./bin/difftool", diff --git a/packages/eslint-config-hubspot/index.js b/packages/eslint-config-hubspot/index.js index fc0dcf2d07..dfcb042a63 100644 --- a/packages/eslint-config-hubspot/index.js +++ b/packages/eslint-config-hubspot/index.js @@ -1,7 +1,8 @@ module.exports = { extends: [ 'eslint-config-hubspot/base', - 'eslint-config-hubspot/rules/react', + 'eslint-config-hubspot/rules/strict', + 'eslint-config-hubspot/rules/react' ].map(require.resolve), rules: {} }; diff --git a/packages/eslint-config-hubspot/legacy.js b/packages/eslint-config-hubspot/legacy.js index 08c5661fa5..8b3fd12161 100644 --- a/packages/eslint-config-hubspot/legacy.js +++ b/packages/eslint-config-hubspot/legacy.js @@ -4,7 +4,6 @@ module.exports = { 'eslint-config-hubspot/rules/errors', 'eslint-config-hubspot/rules/legacy', 'eslint-config-hubspot/rules/node', - 'eslint-config-hubspot/rules/strict', 'eslint-config-hubspot/rules/style', 'eslint-config-hubspot/rules/variables' ].map(require.resolve), diff --git a/packages/eslint-config-hubspot/package.json b/packages/eslint-config-hubspot/package.json index 182c47db1f..7e6332ecc1 100644 --- a/packages/eslint-config-hubspot/package.json +++ b/packages/eslint-config-hubspot/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-hubspot", - "version": "2.0.0", + "version": "2.1.0", "description": "HubSpot's ESLint config, following our styleguide", "main": "index.js", "scripts": { @@ -33,7 +33,7 @@ "devDependencies": { "babel-tape-runner": "1.2.0", "eslint": "^1.10.3", - "eslint-plugin-react": "^3.11.3", + "eslint-plugin-react": "^3.12.0", "faucet": "0.0.1", "react": "^0.13.3", "tape": "^4.2.2" diff --git a/packages/eslint-config-hubspot/rules/best-practices.js b/packages/eslint-config-hubspot/rules/best-practices.js index 53c8a047b9..b625912761 100644 --- a/packages/eslint-config-hubspot/rules/best-practices.js +++ b/packages/eslint-config-hubspot/rules/best-practices.js @@ -74,7 +74,9 @@ module.exports = { // var foo = 'Copyright \251'; 'no-octal-escape': 2, // disallow reassignment of function parameters - 'no-param-reassign': 2, + // 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 diff --git a/packages/eslint-config-hubspot/rules/legacy.js b/packages/eslint-config-hubspot/rules/legacy.js index 1d0c518316..e94c774f26 100644 --- a/packages/eslint-config-hubspot/rules/legacy.js +++ b/packages/eslint-config-hubspot/rules/legacy.js @@ -2,8 +2,6 @@ module.exports = { 'rules': { // specify the maximum depth that blocks can be nested 'max-depth': [0, 4], - // specify the maximum length of a line in your program - 'max-len': [0, 80, 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 diff --git a/packages/eslint-config-hubspot/rules/react.js b/packages/eslint-config-hubspot/rules/react.js index 4d41cdb006..c44ebdc72a 100644 --- a/packages/eslint-config-hubspot/rules/react.js +++ b/packages/eslint-config-hubspot/rules/react.js @@ -5,10 +5,15 @@ module.exports = { '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, + '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, 'always'], @@ -17,52 +22,97 @@ module.exports = { 'react/jsx-closing-bracket-location': [2, {'selfClosing': 'tag-aligned', 'nonEmpty': 'after-props'}], // 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, + '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, + '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, + '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, + '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, + 'react/jsx-uses-react': [2], // 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': [0, {'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': 0, // 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, + 'react/no-multi-comp': [2, {'ignoreStateless': false}], + // 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': [0, '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, + '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, + '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, diff --git a/packages/eslint-config-hubspot/rules/style.js b/packages/eslint-config-hubspot/rules/style.js index 4ad35174d6..af8e402c8c 100644 --- a/packages/eslint-config-hubspot/rules/style.js +++ b/packages/eslint-config-hubspot/rules/style.js @@ -10,7 +10,7 @@ module.exports = { 'comma-spacing': [2, {'before': false, 'after': true}], // enforce one true comma style 'comma-style': [2, 'last'], - // require or disallow padding inside computed properties + // disallow padding inside computed properties 'computed-property-spacing': [2, 'never'], // enforces consistent naming when capturing the current execution context 'consistent-this': 0, @@ -34,6 +34,18 @@ module.exports = { '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': [0, { + 'code': 100, + 'comments': 100, + 'commentLength': 100, + 'tabWidth': 2, + 'ignoreUrls': false, + 'ignorePattern': null, + 'ignoreTrailingComments': false, + 'ignoreComments': false + }], // specify the maximum depth callbacks can be nested 'max-nested-callbacks': 0, // require a capital letter for constructors @@ -68,8 +80,8 @@ module.exports = { 'no-underscore-dangle': 0, // disallow the use of Boolean literals in conditional expressions 'no-unneeded-ternary': 0, - // require or disallow padding inside curly braces - 'object-curly-spacing': 0, + // require padding inside curly braces + 'object-curly-spacing': [0, 'always'], // allow just one var statement per function 'one-var': [2, 'never'], // require assignment operator shorthand where possible or prohibit it entirely @@ -98,7 +110,7 @@ module.exports = { '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, 'never'], + 'space-before-function-paren': [0, { 'anonymous': 'never', 'named': 'never' }], // require or disallow spaces inside parentheses 'space-in-parens': [2, 'never'], // require spaces around operators diff --git a/react/README.md b/react/README.md index b177af82ce..cf2dbcda28 100644 --- a/react/README.md +++ b/react/README.md @@ -8,19 +8,20 @@ ## 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) 1. [Quotes](#quotes) 1. [Spacing](#spacing) 1. [Props](#props) - 1. [Set State](#set-state) 1. [Parentheses](#parentheses) 1. [Tags](#tags) 1. [Methods](#methods) - 1. [Guidelines](#guidelines) 1. [Ordering](#ordering) - + 1. [`isMounted`](#ismounted) + 1. [Set State](#set-state) + 1. [Guidelines](#guidelines) ## Basic Rules @@ -28,29 +29,27 @@ - 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. + eslint rules: [`react/prefer-es6-class`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/prefer-es6-class.md). - 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
; - } - }); + ```javascript + // bad + const Listing = React.createClass({ + render() { + return
; + } + }); - // good - class Listing extends React.Component { - render() { - return
; + // good + class Listing extends React.Component { + render() { + return
; + } } - } - ``` - + ``` ## Naming @@ -62,10 +61,10 @@ ```javascript // bad - const reservationCard = require('./ReservationCard'); + import reservationCard from './ReservationCard'; // good - const ReservationCard = require('./ReservationCard'); + import ReservationCard from './ReservationCard'; // bad const ReservationItem = ; @@ -74,21 +73,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 @@ -102,11 +102,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). + 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 @@ -130,14 +130,14 @@ ``` - ## Quotes + - Always use double quotes (`"`) for JSX attributes, but single quotes for all other JS. - > 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. + > 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). + eslint rules: [`jsx-quotes`](http://eslint.org/docs/rules/jsx-quotes). ```javascript // bad @@ -156,9 +156,10 @@ ``` - ## Spacing + - Always include a single space in your self-closing tag. + ```javascript // bad @@ -174,9 +175,10 @@ ``` - ## Props + - Always use camelCase for prop names. + ```javascript // bad ; @@ -232,11 +237,11 @@ }); ``` - - Always provide defaults for non-required `propTypes` + - Always provide defaults for non-required `propTypes` ```javascript // bad (missing default value for `b` and `z` props) - var Component = React.createClass({ + const Component = React.createClass({ propTypes: { a: React.PropTypes.any.isRequired, b: React.PropTypes.string, @@ -245,7 +250,7 @@ }); // good - var Component = React.createClass({ + const Component = React.createClass({ propTypes: { a: React.PropTypes.any.isRequired, b: React.PropTypes.string, @@ -261,26 +266,14 @@ }); ``` +## Parentheses -## Set State - - Don't `setState` in `componentDidMount` - - Updating the state after a component mount will trigger a second render() call and can lead to property/layout thrashing. This **does not apply to `setState` in event handlers** added here. - - If you need to do something to change state here, use a function prop that can change state at the top level and pass new data down accordingly. - - - - Don't `setState` in `componentDidUpdate` - - Updating the state after a component update will trigger a second render() call and can lead to property/layout thrashing. - - If you need to do something to change state here, use a function prop that can change state at the top level and pass new data down accordingly. + - 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). -## Parentheses - - Wrap JSX tags in parentheses when they span more than one line: ```javascript - /// bad + // bad render() { return @@ -303,11 +296,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). + eslint rules: [`react/self-closing-comp`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/self-closing-comp.md). ```javascript // bad @@ -319,7 +312,7 @@ - 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). + 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 @@ -334,15 +327,52 @@ /> ``` - ## Methods + + - Bind event handlers for the render method in the constructor. + + > Why? A bind call in a the render path create 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 }); @@ -354,10 +384,109 @@ } // 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. Getters, setters, event handlers, helper methods, etc. + 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} + } + } + + Link.propTypes = propTypes; + Link.defaultProps = defaultProps; ``` + - Ordering for `React.createClass`: + + 1. `displayName` + 1. `mixins` + 1. `propTypes` + 1. `contextTypes` + 1. `childContextTypes` + 1. `statics` + 1. `defaultProps` + 1. `getDefaultProps` + 1. `getInitialState` + 1. `state` + 1. `getChildContext` + 1. `componentWillMount` + 1. `componentDidMount` + 1. `componentWillReceiveProps` + 1. `shouldComponentUpdate` + 1. `componentWillUpdate` + 1. `componentDidUpdate` + 1. `componentWillUnmount` + 1. Getters, setters, event handlers, helper methods, etc. + 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). + +## Set State + - Don't `setState` in `componentDidMount` + + Updating the state after a component mount will trigger a second render() call and can lead to property/layout thrashing. This **does not apply to `setState` in event handlers** added here. + + If you need to do something to change state here, use a function prop that can change state at the top level and pass new data down accordingly. + + + - Don't `setState` in `componentDidUpdate` + + Updating the state after a component update will trigger a second render() call and can lead to property/layout thrashing. + + If you need to do something to change state here, use a function prop that can change state at the top level and pass new data down accordingly. + + ## GuideLines These are guidelines more than rules, and they will likely be more controversial than those listed above. This is where we collaborate :) @@ -413,7 +542,7 @@ These are guidelines more than rules, and they will likely be more controversial Prefer to pass props/state values into your helper methods instead of access via `this` in the method body. This enables you to extract them to helper objects without refactoring, as well as easily write automated tests without needing to setup a complete stateful component. - ```js + ```javascript // discouraged (stateful method, harder to test and extract/refactor) export default React.createClass({ ... @@ -449,77 +578,4 @@ These are guidelines more than rules, and they will likely be more controversial }); ``` -## 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. Getters, setters, event handlers, helper methods, etc. - 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} - } - } - - Link.propTypes = propTypes; - Link.defaultProps = defaultProps; - ``` - - - - Ordering for React.createClass: - - 1. displayName - 1. mixins - 1. propTypes - 1. contextTypes - 1. childContextTypes - 1. statics - 1. defaultProps - 1. getDefaultProps - 1. getInitialState - 1. state - 1. getChildContext - 1. componentWillMount - 1. componentDidMount - 1. componentWillReceiveProps - 1. shouldComponentUpdate - 1. componentWillUpdate - 1. componentDidUpdate - 1. componentWillUnmount - 1. Getters, setters, event handlers, helper methods, etc. - 1. Optional render methods like renderNavigation() or renderProfilePicture() - 1. render - **[⬆ back to top](#table-of-contents)** From e11092bba6f5c33fc7410fad78c8bba00b46fa3e Mon Sep 17 00:00:00 2001 From: Nick Hwang Date: Wed, 30 Dec 2015 22:27:47 -0500 Subject: [PATCH 23/54] Update git remote grep pattern --- bin/difftool | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/difftool b/bin/difftool index 22b6dd7767..c22e11aa82 100755 --- a/bin/difftool +++ b/bin/difftool @@ -31,7 +31,7 @@ function rename() { } # Add Airbnb git remote -if [[ -z $(git remote -v | grep "$AIRBNB_REMOTE $AIRBNB_GIT (fetch)") ]]; then +if [[ -z $(git remote -v | grep -e "$AIRBNB_REMOTE\s\+$AIRBNB_GIT\s\+(fetch)") ]]; then git remote add "$AIRBNB_REMOTE" "$AIRBNB_GIT" fi diff --git a/package.json b/package.json index 4799579699..d7b2299d2b 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "version": "2.1.0", "description": "HubSpot's version of a mostly reasonable approach to JavaScript", "scripts": { - "update": "./bin/difftool", + "difftool": "./bin/difftool", "cleanup ": "./bin/cleanup", "publish:config": "cd packages/eslint-config-hubspot && npm publish", "publish:all": "npm publish && npm run publish:config" From ff8eadb5939d3cd9369befba60a505ec68f9e2ac Mon Sep 17 00:00:00 2001 From: Nick Hwang Date: Wed, 30 Dec 2015 23:12:01 -0500 Subject: [PATCH 24/54] Damn whitespace... --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d7b2299d2b..e45d058c39 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "HubSpot's version of a mostly reasonable approach to JavaScript", "scripts": { "difftool": "./bin/difftool", - "cleanup ": "./bin/cleanup", + "cleanup": "./bin/cleanup", "publish:config": "cd packages/eslint-config-hubspot && npm publish", "publish:all": "npm publish && npm run publish:config" }, From 5cbe2ebbe67728eb3ee4c63cd57090ca5247da0f Mon Sep 17 00:00:00 2001 From: Nick Hwang Date: Wed, 30 Dec 2015 23:18:32 -0500 Subject: [PATCH 25/54] Fix max-len rule --- package.json | 2 +- packages/eslint-config-hubspot/package.json | 2 +- packages/eslint-config-hubspot/rules/style.js | 8 +------- 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index e45d058c39..e4e7108ad3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hubspot-style", - "version": "2.1.0", + "version": "2.1.1", "description": "HubSpot's version of a mostly reasonable approach to JavaScript", "scripts": { "difftool": "./bin/difftool", diff --git a/packages/eslint-config-hubspot/package.json b/packages/eslint-config-hubspot/package.json index 7e6332ecc1..ecec48b112 100644 --- a/packages/eslint-config-hubspot/package.json +++ b/packages/eslint-config-hubspot/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-hubspot", - "version": "2.1.0", + "version": "2.1.1", "description": "HubSpot's ESLint config, following our styleguide", "main": "index.js", "scripts": { diff --git a/packages/eslint-config-hubspot/rules/style.js b/packages/eslint-config-hubspot/rules/style.js index af8e402c8c..52848ed1d2 100644 --- a/packages/eslint-config-hubspot/rules/style.js +++ b/packages/eslint-config-hubspot/rules/style.js @@ -36,14 +36,8 @@ module.exports = { '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': [0, { - 'code': 100, - 'comments': 100, - 'commentLength': 100, - 'tabWidth': 2, + 'max-len': [0, 100, 2, { 'ignoreUrls': false, - 'ignorePattern': null, - 'ignoreTrailingComments': false, 'ignoreComments': false }], // specify the maximum depth callbacks can be nested From 7fb2b8805dae31239bdf765cf59d57d969856c3f Mon Sep 17 00:00:00 2001 From: Nick Hwang Date: Wed, 30 Dec 2015 23:45:32 -0500 Subject: [PATCH 26/54] Use non-broken version of eslint-plugin-react --- package.json | 2 +- packages/eslint-config-hubspot/package.json | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index e4e7108ad3..407255ffc2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hubspot-style", - "version": "2.1.1", + "version": "2.1.2", "description": "HubSpot's version of a mostly reasonable approach to JavaScript", "scripts": { "difftool": "./bin/difftool", diff --git a/packages/eslint-config-hubspot/package.json b/packages/eslint-config-hubspot/package.json index ecec48b112..c754d80980 100644 --- a/packages/eslint-config-hubspot/package.json +++ b/packages/eslint-config-hubspot/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-hubspot", - "version": "2.1.1", + "version": "2.1.2", "description": "HubSpot's ESLint config, following our styleguide", "main": "index.js", "scripts": { @@ -33,12 +33,13 @@ "devDependencies": { "babel-tape-runner": "1.2.0", "eslint": "^1.10.3", - "eslint-plugin-react": "^3.12.0", + "eslint-plugin-react": "~3.12.0", "faucet": "0.0.1", "react": "^0.13.3", "tape": "^4.2.2" }, "peerDependencies": { - "eslint": ">=1.0.0" + "eslint": "^1.0.0", + "eslint-plugin-react": "~3.12.0" } } From cd267e4d31632d6abe2f8ecb4b89f4e23e332ff3 Mon Sep 17 00:00:00 2001 From: Nick Hwang Date: Thu, 31 Dec 2015 00:12:18 -0500 Subject: [PATCH 27/54] Allow reassign for props (for now...) --- package.json | 2 +- packages/eslint-config-hubspot/package.json | 2 +- packages/eslint-config-hubspot/rules/best-practices.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 407255ffc2..ad1fb438a2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hubspot-style", - "version": "2.1.2", + "version": "2.1.3", "description": "HubSpot's version of a mostly reasonable approach to JavaScript", "scripts": { "difftool": "./bin/difftool", diff --git a/packages/eslint-config-hubspot/package.json b/packages/eslint-config-hubspot/package.json index c754d80980..fdeb571453 100644 --- a/packages/eslint-config-hubspot/package.json +++ b/packages/eslint-config-hubspot/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-hubspot", - "version": "2.1.2", + "version": "2.1.3", "description": "HubSpot's ESLint config, following our styleguide", "main": "index.js", "scripts": { diff --git a/packages/eslint-config-hubspot/rules/best-practices.js b/packages/eslint-config-hubspot/rules/best-practices.js index b625912761..6bb1d759bf 100644 --- a/packages/eslint-config-hubspot/rules/best-practices.js +++ b/packages/eslint-config-hubspot/rules/best-practices.js @@ -76,7 +76,7 @@ module.exports = { // 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 }], + 'no-param-reassign': [2, { 'props': false }], // disallow use of process.env 'no-process-env': 0, // disallow usage of __proto__ property From f0a568ab029ce5f362525fce084e22fc0741bb3d Mon Sep 17 00:00:00 2001 From: Nick Hwang Date: Tue, 5 Jan 2016 10:34:14 -0500 Subject: [PATCH 28/54] Update with airbnb/master@3.0.0 Mostly a version number sync. Rules are the same as `hubspot/javascript@^2.1.3` --- README.md | 24 ++++++++++++++++--- package.json | 2 +- packages/eslint-config-hubspot/CHANGELOG.md | 13 ++++++++++ packages/eslint-config-hubspot/package.json | 6 ++--- packages/eslint-config-hubspot/rules/style.js | 5 ++-- react/README.md | 2 +- 6 files changed, 42 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 0ce0d3a63d..c6cf56592d 100644 --- a/README.md +++ b/README.md @@ -748,18 +748,36 @@ Other Style Guides (from Airbnb) ``` - - [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. 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)** @@ -1779,7 +1797,7 @@ Other Style Guides (from Airbnb) - [19.2](#19.2) Additional trailing comma: **Yup.** - eslint rules: [`no-comma-dangle`](http://eslint.org/docs/rules/no-comma-dangle.html). + 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. diff --git a/package.json b/package.json index ad1fb438a2..5d9391a19d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hubspot-style", - "version": "2.1.3", + "version": "3.0.0", "description": "HubSpot's version of a mostly reasonable approach to JavaScript", "scripts": { "difftool": "./bin/difftool", diff --git a/packages/eslint-config-hubspot/CHANGELOG.md b/packages/eslint-config-hubspot/CHANGELOG.md index bc269e9222..cb48349261 100644 --- a/packages/eslint-config-hubspot/CHANGELOG.md +++ b/packages/eslint-config-hubspot/CHANGELOG.md @@ -1,3 +1,16 @@ +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) diff --git a/packages/eslint-config-hubspot/package.json b/packages/eslint-config-hubspot/package.json index fdeb571453..4eed3b6696 100644 --- a/packages/eslint-config-hubspot/package.json +++ b/packages/eslint-config-hubspot/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-hubspot", - "version": "2.1.3", + "version": "3.0.0", "description": "HubSpot's ESLint config, following our styleguide", "main": "index.js", "scripts": { @@ -33,13 +33,13 @@ "devDependencies": { "babel-tape-runner": "1.2.0", "eslint": "^1.10.3", - "eslint-plugin-react": "~3.12.0", + "eslint-plugin-react": "^3.14.0", "faucet": "0.0.1", "react": "^0.13.3", "tape": "^4.2.2" }, "peerDependencies": { "eslint": "^1.0.0", - "eslint-plugin-react": "~3.12.0" + "eslint-plugin-react": "^3.0.0" } } diff --git a/packages/eslint-config-hubspot/rules/style.js b/packages/eslint-config-hubspot/rules/style.js index 52848ed1d2..f34e9a17fc 100644 --- a/packages/eslint-config-hubspot/rules/style.js +++ b/packages/eslint-config-hubspot/rules/style.js @@ -85,7 +85,8 @@ module.exports = { // enforce padding within blocks 'padded-blocks': [2, 'never'], // require quotes around object literal property names - 'quote-props': 0, + // http://eslint.org/docs/rules/quote-props.html + 'quote-props': [0, 'as-needed', { 'keywords': true, '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 @@ -104,7 +105,7 @@ module.exports = { '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': [0, { 'anonymous': 'never', 'named': 'never' }], + 'space-before-function-paren': [0, { 'anonymous': 'always', 'named': 'never' }], // require or disallow spaces inside parentheses 'space-in-parens': [2, 'never'], // require spaces around operators diff --git a/react/README.md b/react/README.md index cf2dbcda28..6ba1b97918 100644 --- a/react/README.md +++ b/react/README.md @@ -331,7 +331,7 @@ - Bind event handlers for the render method in the constructor. - > Why? A bind call in a the render path create a brand new function on every single render. + > 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). From 3251baac8a94bd5570b80b9494cc326b82dfac41 Mon Sep 17 00:00:00 2001 From: Nick Hwang Date: Wed, 6 Jan 2016 18:37:22 -0500 Subject: [PATCH 29/54] Update with airbnb/master@3.0.1 Minor change regarding quoted keywords. Rule is disabled on our style guide so no differences from `HubSpot/javascript@3.0.0`. --- README.md | 28 +++++++++++++++++-- package.json | 2 +- packages/eslint-config-hubspot/CHANGELOG.md | 4 +++ packages/eslint-config-hubspot/package.json | 2 +- packages/eslint-config-hubspot/rules/style.js | 2 +- 5 files changed, 33 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index c6cf56592d..5ea88af38f 100644 --- a/README.md +++ b/README.md @@ -292,6 +292,28 @@ Other Style Guides (from Airbnb) }; ``` + - [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 @@ -361,8 +383,8 @@ Other Style Guides (from Airbnb) } // good - function getFullName(obj) { - const { firstName, lastName } = obj; + function getFullName(user) { + const { firstName, lastName } = user; return `${firstName} ${lastName}`; } @@ -1891,6 +1913,8 @@ Other Style Guides (from Airbnb) - [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'; diff --git a/package.json b/package.json index 5d9391a19d..254d613211 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hubspot-style", - "version": "3.0.0", + "version": "3.0.1", "description": "HubSpot's version of a mostly reasonable approach to JavaScript", "scripts": { "difftool": "./bin/difftool", diff --git a/packages/eslint-config-hubspot/CHANGELOG.md b/packages/eslint-config-hubspot/CHANGELOG.md index cb48349261..5877ff5092 100644 --- a/packages/eslint-config-hubspot/CHANGELOG.md +++ b/packages/eslint-config-hubspot/CHANGELOG.md @@ -1,3 +1,7 @@ +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) diff --git a/packages/eslint-config-hubspot/package.json b/packages/eslint-config-hubspot/package.json index 4eed3b6696..4707c3c2b1 100644 --- a/packages/eslint-config-hubspot/package.json +++ b/packages/eslint-config-hubspot/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-hubspot", - "version": "3.0.0", + "version": "3.0.1", "description": "HubSpot's ESLint config, following our styleguide", "main": "index.js", "scripts": { diff --git a/packages/eslint-config-hubspot/rules/style.js b/packages/eslint-config-hubspot/rules/style.js index f34e9a17fc..e3f3c22512 100644 --- a/packages/eslint-config-hubspot/rules/style.js +++ b/packages/eslint-config-hubspot/rules/style.js @@ -86,7 +86,7 @@ module.exports = { 'padded-blocks': [2, 'never'], // require quotes around object literal property names // http://eslint.org/docs/rules/quote-props.html - 'quote-props': [0, 'as-needed', { 'keywords': true, 'unnecessary': true, 'numbers': false }], + 'quote-props': [0, '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 From 7e7f2de1526f9341ed24d900712bc37140dfc3c2 Mon Sep 17 00:00:00 2001 From: Nick Hwang Date: Wed, 6 Jan 2016 22:44:10 -0500 Subject: [PATCH 30/54] Update with airbnb/master@3.0.2 Ignore URLs in `max-len` --- README.md | 2 +- package.json | 2 +- packages/eslint-config-hubspot/CHANGELOG.md | 4 ++++ packages/eslint-config-hubspot/package.json | 2 +- packages/eslint-config-hubspot/rules/style.js | 2 +- 5 files changed, 8 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 5ea88af38f..4095b3848e 100644 --- a/README.md +++ b/README.md @@ -726,7 +726,7 @@ Other Style Guides (from Airbnb) }); ``` - - [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. diff --git a/package.json b/package.json index 254d613211..48bd0129a2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hubspot-style", - "version": "3.0.1", + "version": "3.0.2", "description": "HubSpot's version of a mostly reasonable approach to JavaScript", "scripts": { "difftool": "./bin/difftool", diff --git a/packages/eslint-config-hubspot/CHANGELOG.md b/packages/eslint-config-hubspot/CHANGELOG.md index 5877ff5092..6a241140a4 100644 --- a/packages/eslint-config-hubspot/CHANGELOG.md +++ b/packages/eslint-config-hubspot/CHANGELOG.md @@ -1,3 +1,7 @@ +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 diff --git a/packages/eslint-config-hubspot/package.json b/packages/eslint-config-hubspot/package.json index 4707c3c2b1..753d96b5b6 100644 --- a/packages/eslint-config-hubspot/package.json +++ b/packages/eslint-config-hubspot/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-hubspot", - "version": "3.0.1", + "version": "3.0.2", "description": "HubSpot's ESLint config, following our styleguide", "main": "index.js", "scripts": { diff --git a/packages/eslint-config-hubspot/rules/style.js b/packages/eslint-config-hubspot/rules/style.js index e3f3c22512..0ff1f157cf 100644 --- a/packages/eslint-config-hubspot/rules/style.js +++ b/packages/eslint-config-hubspot/rules/style.js @@ -37,7 +37,7 @@ module.exports = { // specify the maximum length of a line in your program // https://github.com/eslint/eslint/blob/master/docs/rules/max-len.md 'max-len': [0, 100, 2, { - 'ignoreUrls': false, + 'ignoreUrls': true, 'ignoreComments': false }], // specify the maximum depth callbacks can be nested From 9804080fcc999776f4168796403a8953d151416b Mon Sep 17 00:00:00 2001 From: Nick Hwang Date: Fri, 8 Jan 2016 09:12:30 -0500 Subject: [PATCH 31/54] Update with airbnb/master@3.1.0 Allow mutliple stateless components in a single file --- README.md | 2 +- package.json | 2 +- packages/eslint-config-hubspot/CHANGELOG.md | 4 ++++ packages/eslint-config-hubspot/package.json | 2 +- packages/eslint-config-hubspot/rules/react.js | 2 +- react/README.md | 1 + 6 files changed, 9 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 4095b3848e..f4a2a86e80 100644 --- a/README.md +++ b/README.md @@ -1505,7 +1505,7 @@ Other Style Guides (from Airbnb) }); ``` - - [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). diff --git a/package.json b/package.json index 48bd0129a2..881b0e1d91 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hubspot-style", - "version": "3.0.2", + "version": "3.1.0", "description": "HubSpot's version of a mostly reasonable approach to JavaScript", "scripts": { "difftool": "./bin/difftool", diff --git a/packages/eslint-config-hubspot/CHANGELOG.md b/packages/eslint-config-hubspot/CHANGELOG.md index 6a241140a4..0cbe0e1357 100644 --- a/packages/eslint-config-hubspot/CHANGELOG.md +++ b/packages/eslint-config-hubspot/CHANGELOG.md @@ -1,3 +1,7 @@ +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) diff --git a/packages/eslint-config-hubspot/package.json b/packages/eslint-config-hubspot/package.json index 753d96b5b6..c3c3d34499 100644 --- a/packages/eslint-config-hubspot/package.json +++ b/packages/eslint-config-hubspot/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-hubspot", - "version": "3.0.2", + "version": "3.1.0", "description": "HubSpot's ESLint config, following our styleguide", "main": "index.js", "scripts": { diff --git a/packages/eslint-config-hubspot/rules/react.js b/packages/eslint-config-hubspot/rules/react.js index c44ebdc72a..5bcd2e6543 100644 --- a/packages/eslint-config-hubspot/rules/react.js +++ b/packages/eslint-config-hubspot/rules/react.js @@ -91,7 +91,7 @@ module.exports = { 'react/no-is-mounted': 0, // 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': false}], + '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, diff --git a/react/README.md b/react/README.md index 6ba1b97918..7be63b5591 100644 --- a/react/README.md +++ b/react/README.md @@ -26,6 +26,7 @@ ## 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. From 6ca3b1651847e03448b7e5aa5ab00d7dccc42bac Mon Sep 17 00:00:00 2001 From: Nick Hwang Date: Fri, 15 Jan 2016 09:36:09 -0800 Subject: [PATCH 32/54] Fix config readme to omit babel-eslint --- packages/eslint-config-hubspot/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/eslint-config-hubspot/README.md b/packages/eslint-config-hubspot/README.md index 181b8ce34f..dbd5c9559b 100644 --- a/packages/eslint-config-hubspot/README.md +++ b/packages/eslint-config-hubspot/README.md @@ -16,7 +16,7 @@ We export three ESLint configurations for your usage. 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-hubspot babel-eslint eslint-plugin-react eslint` +1. `npm install --save-dev eslint-config-hubspot eslint-plugin-react eslint` 2. add `"extends": "hubspot"` to your .eslintrc ### eslint-config-hubspot/base From bf9fd5e81f0a8256ec65da0959d3447082a2aa5d Mon Sep 17 00:00:00 2001 From: Nick Hwang Date: Sun, 24 Jan 2016 15:33:28 -0500 Subject: [PATCH 33/54] Update with airbnb/master@4.0.0 In addition to the changes in `4.0.0`, the following HubSpot variant rules were also updated: - Add no parentheses around object literals in style guide - Closes #14 - Ignore `react/jsx-closing-bracket-location#nonEmpty` - Closes #15 --- README.md | 155 ++++++++++++++---- package.json | 2 +- packages/eslint-config-hubspot/.babelrc | 7 + packages/eslint-config-hubspot/CHANGELOG.md | 10 ++ packages/eslint-config-hubspot/package.json | 15 +- .../rules/.eslintrc.json | 5 + .../rules/best-practices.js | 5 +- packages/eslint-config-hubspot/rules/es6.js | 8 + packages/eslint-config-hubspot/rules/react.js | 20 +-- packages/eslint-config-hubspot/rules/style.js | 17 +- .../eslint-config-hubspot/rules/variables.js | 2 +- react/README.md | 62 +++++-- 12 files changed, 232 insertions(+), 76 deletions(-) create mode 100644 packages/eslint-config-hubspot/.babelrc create mode 100644 packages/eslint-config-hubspot/rules/.eslintrc.json diff --git a/README.md b/README.md index f4a2a86e80..2944055e31 100644 --- a/README.md +++ b/README.md @@ -114,6 +114,8 @@ Other Style Guides (from Airbnb) eslint rules: [`no-var`](http://eslint.org/docs/rules/no-var.html). + jscs rules: [`disallowVar`](http://jscs.info/rule/disallowVar). + ```javascript // bad var count = 1; @@ -158,6 +160,8 @@ Other Style Guides (from Airbnb) - [3.2](#3.2) If your code will be executed in browsers in script context, don't use [reserved words](http://es5.github.io/#x7.6.1) as keys. It won't work in IE8. [More info](https://github.com/airbnb/javascript/issues/61). It’s OK to use them in ES6 modules and server-side code. + jscs rules: [`disallowIdentiferNames`](http://jscs.info/rule/disallowIdentifierNames). + ```javascript // bad const superman = { @@ -174,6 +178,8 @@ Other Style Guides (from Airbnb) - [3.3](#3.3) Use readable synonyms in place of reserved words. + jscs rules: [`disallowIdentiferNames`](http://jscs.info/rule/disallowIdentifierNames). + ```javascript // bad const superman = { @@ -222,6 +228,8 @@ Other Style Guides (from Airbnb) eslint rules: [`object-shorthand`](http://eslint.org/docs/rules/object-shorthand.html). + jscs rules: [`requireEnhancedObjectLiterals`](http://jscs.info/rule/requireEnhancedObjectLiterals). + ```javascript // bad const atom = { @@ -249,6 +257,8 @@ Other Style Guides (from Airbnb) eslint rules: [`object-shorthand`](http://eslint.org/docs/rules/object-shorthand.html). + jscs rules: [`requireEnhancedObjectLiterals`](http://jscs.info/rule/requireEnhancedObjectLiterals). + ```javascript const lukeSkywalker = 'Luke Skywalker'; @@ -298,6 +308,8 @@ Other Style Guides (from Airbnb) eslint rules: [`quote-props`](http://eslint.org/docs/rules/quote-props.html). + jscs rules: [`disallowQuotedKeysInObjects`](http://jscs.info/rule/disallowQuotedKeysInObjects). + ```javascript // bad const bad = { @@ -314,6 +326,22 @@ Other Style Guides (from Airbnb) }; ``` + - [3.9](#3.9) Don't wrap object literals in extra parentheses + + ```javascript + // bad + const bad = ({ + hello: 'world', + foo: 'bar' + }); + + // good + const bad = { + hello: 'world', + foo: 'bar' + }; + ``` + **[⬆ back to top](#table-of-contents)** ## Arrays @@ -373,6 +401,8 @@ Other Style Guides (from Airbnb) > Why? Destructuring saves you from creating temporary references for those properties. + jscs rules: [`requireObjectDestructuring`](http://jscs.info/rule/requireObjectDestructuring). + ```javascript // bad function getFullName(user) { @@ -396,6 +426,8 @@ Other Style Guides (from Airbnb) - [5.2](#5.2) Use array destructuring. + jscs rules: [`requireArrayDestructuring`](http://jscs.info/rule/requireArrayDestructuring). + ```javascript const arr = [1, 2, 3, 4]; @@ -440,6 +472,8 @@ Other Style Guides (from Airbnb) eslint rules: [`quotes`](http://eslint.org/docs/rules/quotes.html). + jscs rules: [`validateQuoteMarks`](http://jscs.info/rule/validateQuoteMarks). + ```javascript // bad const name = "Capt. Janeway"; @@ -474,6 +508,8 @@ Other Style Guides (from Airbnb) eslint rules: [`prefer-template`](http://eslint.org/docs/rules/prefer-template.html). + jscs rules: [`requireTemplateStrings`](http://jscs.info/rule/requireTemplateStrings). + ```javascript // bad function sayHi(name) { @@ -501,6 +537,8 @@ Other Style Guides (from Airbnb) > 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. + jscs rules: [`requireFunctionDeclarations`](http://jscs.info/rule/requireFunctionDeclarations). + ```javascript // bad const foo = function () { @@ -511,17 +549,25 @@ Other Style Guides (from Airbnb) } ``` - - [7.2](#7.2) Function expressions: + - [7.2](#7.2) Immediately invoked function expressions: + + > Why? An immediately invoked function expression is a single unit - wrapping both it, and its invocation parens, in parens, cleanly expresses this. Note that in a world with modules everywhere, you almost never need an IIFE. + + eslint rules: [`wrap-iife`](http://eslint.org/docs/rules/wrap-iife.html). + + jscs rules: [`requireParenthesesAroundIIFE`](http://jscs.info/rule/requireParenthesesAroundIIFE). ```javascript // immediately-invoked function expression (IIFE) - (() => { + (function () { console.log('Welcome to the Internet. Please follow me.'); - })(); + }()); ``` - [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. + eslint rules: [`no-loop-func`](http://eslint.org/docs/rules/no-loop-func.html). + - [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 @@ -712,6 +758,8 @@ Other Style Guides (from Airbnb) eslint rules: [`prefer-arrow-callback`](http://eslint.org/docs/rules/prefer-arrow-callback.html), [`arrow-spacing`](http://eslint.org/docs/rules/arrow-spacing.html). + jscs rules: [`requireArrowFunctions`](http://jscs.info/rule/requireArrowFunctions). + ```javascript // bad [1, 2, 3].map(function (x) { @@ -734,6 +782,8 @@ Other Style Guides (from Airbnb) eslint rules: [`arrow-parens`](http://eslint.org/docs/rules/arrow-parens.html), [`arrow-body-style`](http://eslint.org/docs/rules/arrow-body-style.html). + jscs rules: [`disallowParenthesesAroundArrowParam`](http://jscs.info/rule/disallowParenthesesAroundArrowParam), [`requireShorthandArrowFunctions`](http://jscs.info/rule/requireShorthandArrowFunctions). + ```javascript // good [1, 2, 3].map(number => `A string containing the ${number}.`); @@ -776,6 +826,8 @@ Other Style Guides (from Airbnb) eslint rules: [`arrow-parens`](http://eslint.org/docs/rules/arrow-parens.html). + jscs rules: [`disallowParenthesesAroundArrowParam`](http://jscs.info/rule/disallowParenthesesAroundArrowParam). + ```js // bad [1, 2, 3].map((x) => x * x); @@ -987,7 +1039,7 @@ Other Style Guides (from Airbnb) // good let sum = 0; - numbers.forEach((num) => sum += num); + numbers.forEach(num => sum += num); sum === 15; // best (use the functional force) @@ -1008,6 +1060,8 @@ Other Style Guides (from Airbnb) eslint rules: [`dot-notation`](http://eslint.org/docs/rules/dot-notation.html). + jscs rules: [`requireDotNotation`](http://jscs.info/rule/requireDotNotation). + ```javascript const luke = { jedi: true, @@ -1057,6 +1111,8 @@ Other Style Guides (from Airbnb) eslint rules: [`one-var`](http://eslint.org/docs/rules/one-var.html). + jscs rules: [`disallowMultipleVarDecl`](http://jscs.info/rule/disallowMultipleVarDecl). + ```javascript // bad const items = getItems(), @@ -1105,45 +1161,36 @@ Other Style Guides (from Airbnb) > Why? `let` and `const` are block scoped and not function scoped. ```javascript - // good - function () { - test(); - console.log('doing stuff..'); - - //..other stuff.. - + // bad - unnecessary function call + function checkName(hasName) { const name = getName(); - if (name === 'test') { + if (hasName === 'test') { return false; } - return name; - } - - // bad - unnecessary function call - function (hasName) { - const name = getName(); - - if (!hasName) { + if (name === 'test') { + this.setName(''); return false; } - this.setFirstName(name); - - return true; + return name; } // good - function (hasName) { - if (!hasName) { + function checkName(hasName) { + if (hasName === 'test') { return false; } const name = getName(); - this.setFirstName(name); - return true; + if (name === 'test') { + this.setName(''); + return false; + } + + return name; } ``` @@ -1170,7 +1217,7 @@ Other Style Guides (from Airbnb) var declaredButNotAssigned = true; } - // The interpreter is hoisting the variable + // the interpreter is hoisting the variable // declaration to the top of the scope, // which means our example could be rewritten as: function example() { @@ -1262,9 +1309,9 @@ Other Style Guides (from Airbnb) + **Strings** evaluate to **false** if an empty string `''`, otherwise **true** ```javascript - if ([0]) { + if ([0] && []) { // true - // An array is an object, objects evaluate to true + // An array (even an empty one) is an object, objects will evaluate to true } ``` @@ -1328,6 +1375,8 @@ Other Style Guides (from Airbnb) eslint rules: [`brace-style`](http://eslint.org/docs/rules/brace-style.html). + jscs rules: [`disallowNewlineBeforeBlockStatements`](http://jscs.info/rule/disallowNewlineBeforeBlockStatements). + ```javascript // bad if (test) { @@ -1460,6 +1509,8 @@ Other Style Guides (from Airbnb) eslint rules: [`indent`](http://eslint.org/docs/rules/indent.html). + jscs rules: [`validateIndentation`](http://jscs.info/rule/validateIndentation). + ```javascript // bad function () { @@ -1481,6 +1532,8 @@ Other Style Guides (from Airbnb) eslint rules: [`space-before-blocks`](http://eslint.org/docs/rules/space-before-blocks.html). + jscs rules: [`requireSpaceBeforeBlockStatements`](http://jscs.info/rule/requireSpaceBeforeBlockStatements). + ```javascript // bad function test(){ @@ -1509,6 +1562,8 @@ Other Style Guides (from Airbnb) 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). + jscs rules: [`requireSpaceAfterKeywords`](http://jscs.info/rule/requireSpaceAfterKeywords). + ```javascript // bad if(isJedi) { @@ -1535,6 +1590,8 @@ Other Style Guides (from Airbnb) eslint rules: [`space-infix-ops`](http://eslint.org/docs/rules/space-infix-ops.html). + jscs rules: [`requireSpaceBeforeBinaryOperators`](http://jscs.info/rule/requireSpaceBeforeBinaryOperators), [`requireSpaceAfterBinaryOperators`](http://jscs.info/rule/requireSpaceAfterBinaryOperators). + ```javascript // bad const x=y+5; @@ -1609,6 +1666,8 @@ Other Style Guides (from Airbnb) - [18.7](#18.7) Leave a blank line after blocks and before the next statement. + jscs rules: [`requirePaddingNewLinesAfterBlocks`](http://jscs.info/rule/requirePaddingNewLinesAfterBlocks). + ```javascript // bad if (foo) { @@ -1668,6 +1727,8 @@ Other Style Guides (from Airbnb) eslint rules: [`padded-blocks`](http://eslint.org/docs/rules/padded-blocks.html). + jscs rules: [`disallowPaddingNewlinesInBlocks`](http://jscs.info/rule/disallowPaddingNewlinesInBlocks). + ```javascript // bad function bar() { @@ -1702,6 +1763,8 @@ Other Style Guides (from Airbnb) eslint rules: [`space-in-parens`](http://eslint.org/docs/rules/space-in-parens.html). + jscs rules: [`disallowSpacesInsideParentheses`](http://jscs.info/rule/disallowSpacesInsideParentheses). + ```javascript // bad function bar( foo ) { @@ -1728,6 +1791,8 @@ Other Style Guides (from Airbnb) eslint rules: [`array-bracket-spacing`](http://eslint.org/docs/rules/array-bracket-spacing.html). + jscs rules: [`disallowSpacesInsideArrayBrackets`](http://jscs.info/rule/disallowSpacesInsideArrayBrackets). + ```javascript // bad const foo = [ 1, 2, 3 ]; @@ -1742,6 +1807,8 @@ Other Style Guides (from Airbnb) eslint rules: [`object-curly-spacing`](http://eslint.org/docs/rules/object-curly-spacing.html). + jscs rules: [`disallowSpacesInsideObjectBrackets`](http://jscs.info/rule/disallowSpacesInsideObjectBrackets). + ```javascript // bad const foo = {clark: 'kent'}; @@ -1756,6 +1823,8 @@ Other Style Guides (from Airbnb) eslint rules: [`max-len`](http://eslint.org/docs/rules/max-len.html). + jscs rules: [`maximumLineLength`](http://jscs.info/rule/maximumLineLength). + ```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!'; @@ -1785,6 +1854,8 @@ Other Style Guides (from Airbnb) eslint rules: [`comma-style`](http://eslint.org/docs/rules/comma-style.html). + jscs rules: [`requireCommaBeforeLineBreak`](http://jscs.info/rule/requireCommaBeforeLineBreak). + ```javascript // bad const story = [ @@ -1821,6 +1892,8 @@ Other Style Guides (from Airbnb) eslint rules: [`comma-dangle`](http://eslint.org/docs/rules/comma-dangle.html). + jscs rules: [`requireTrailingComma`](http://jscs.info/rule/requireTrailingComma). + > 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 @@ -1871,6 +1944,8 @@ Other Style Guides (from Airbnb) eslint rules: [`semi`](http://eslint.org/docs/rules/semi.html). + jscs rules: [`requireSemicolons`](http://jscs.info/rule/requireSemicolons). + ```javascript // bad (function () { @@ -1882,13 +1957,13 @@ Other Style Guides (from Airbnb) (() => { const name = 'Skywalker'; return name; - })(); + }()); // good (guards against the function becoming an argument when two files with IIFEs are concatenated) ;(() => { const name = 'Skywalker'; return name; - })(); + }()); ``` [Read more](http://stackoverflow.com/questions/7365172/semicolon-before-self-invoking-function/7365214%237365214). @@ -1995,6 +2070,8 @@ Other Style Guides (from Airbnb) eslint rules: [`camelcase`](http://eslint.org/docs/rules/camelcase.html). + jscs rules: [`requireCamelCaseOrUpperCaseIdentifiers`](http://jscs.info/rule/requireCamelCaseOrUpperCaseIdentifiers). + ```javascript // bad const OBJEcttsssss = {}; @@ -2008,6 +2085,10 @@ Other Style Guides (from Airbnb) - [22.3](#22.3) Use PascalCase when naming constructors or classes. + eslint rules: [`new-cap`](http://eslint.org/docs/rules/new-cap.html). + + jscs rules: [`requireCapitalizedConstructors`](http://jscs.info/rule/requireCapitalizedConstructors). + ```javascript // bad function user(options) { @@ -2034,6 +2115,8 @@ Other Style Guides (from Airbnb) eslint rules: [`no-underscore-dangle`](http://eslint.org/docs/rules/no-underscore-dangle.html). + jscs rules: [`disallowDanglingUnderscores`](http://jscs.info/rule/disallowDanglingUnderscores). + ```javascript // bad this.__firstName__ = 'Panda'; @@ -2045,6 +2128,8 @@ Other Style Guides (from Airbnb) - [22.5](#22.5) Don't save references to `this`. Use arrow functions or Function#bind. + jscs rules: [`disallowNodeTypes`](http://jscs.info/rule/disallowNodeTypes). + ```javascript // bad function foo() { @@ -2204,6 +2289,8 @@ Other Style Guides (from Airbnb) - [25.1](#25.1) Prefix jQuery object variables with a `$`. + jscs rules: [`requireDollarBeforejQueryAssignment`](http://jscs.info/rule/requireDollarBeforejQueryAssignment). + ```javascript // bad const sidebar = $('.sidebar'); @@ -2493,6 +2580,7 @@ Other Style Guides (from Airbnb) - **Airbnb**: [airbnb/javascript](https://github.com/airbnb/javascript) - **Apartmint**: [apartmint/javascript](https://github.com/apartmint/javascript) - **Avalara**: [avalara/javascript](https://github.com/avalara/javascript) + - **Avant**: [avantcredit/javascript](https://github.com/avantcredit/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) @@ -2545,6 +2633,7 @@ Other Style Guides (from Airbnb) - **TheLadders**: [TheLadders/javascript](https://github.com/TheLadders/javascript) - **T4R Technology**: [T4R-Technology/javascript](https://github.com/T4R-Technology/javascript) - **VoxFeed**: [VoxFeed/javascript-style-guide](https://github.com/VoxFeed/javascript-style-guide) + - **WeBox Studio**: [weboxstudio/javascript](https://github.com/weboxstudio/javascript) - **Weggo**: [Weggo/javascript](https://github.com/Weggo/javascript) - **Zillow**: [zillow/javascript](https://github.com/zillow/javascript) - **ZocDoc**: [ZocDoc/javascript](https://github.com/ZocDoc/javascript) @@ -2587,7 +2676,7 @@ Other Style Guides (from Airbnb) (The MIT License) -Copyright (c) 2014 Airbnb +Copyright (c) 2014-2016 HubSpot Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/package.json b/package.json index 881b0e1d91..9285577fc3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hubspot-style", - "version": "3.1.0", + "version": "4.0.0", "description": "HubSpot's version of a mostly reasonable approach to JavaScript", "scripts": { "difftool": "./bin/difftool", diff --git a/packages/eslint-config-hubspot/.babelrc b/packages/eslint-config-hubspot/.babelrc new file mode 100644 index 0000000000..17f5ebe23a --- /dev/null +++ b/packages/eslint-config-hubspot/.babelrc @@ -0,0 +1,7 @@ +{ + "presets": ["es2015"], + "plugins": [ + "transform-strict-mode", + "transform-export-extensions" + ] +} diff --git a/packages/eslint-config-hubspot/CHANGELOG.md b/packages/eslint-config-hubspot/CHANGELOG.md index 0cbe0e1357..50a4e56b00 100644 --- a/packages/eslint-config-hubspot/CHANGELOG.md +++ b/packages/eslint-config-hubspot/CHANGELOG.md @@ -1,3 +1,13 @@ +4.0.0 / 2016-01-22 +================== + - [breaking] require outer IIFE wrapping; flesh out guide section + - [minor] Add missing `arrow-body-style`, `prefer-template` rules (#678) + - [minor] Add `prefer-arrow-callback` to ES6 rules (to match the guide) (#677) + - [Tests] run `npm run lint` as part of tests; fix errors + - [Tests] use `parallelshell` to parallelize npm run-scripts + - [hubspot] Add rule about no parentheses around object literals + - [hubspot] Ignore `react/jsx-closing-bracket-location#nonEmpty` rule (#15) + 3.1.0 / 2016-01-07 ================== - [minor] Allow multiple stateless components in a single file diff --git a/packages/eslint-config-hubspot/package.json b/packages/eslint-config-hubspot/package.json index c3c3d34499..927eee839a 100644 --- a/packages/eslint-config-hubspot/package.json +++ b/packages/eslint-config-hubspot/package.json @@ -1,11 +1,12 @@ { "name": "eslint-config-hubspot", - "version": "3.1.0", + "version": "4.0.0", "description": "HubSpot's ESLint config, following our styleguide", "main": "index.js", "scripts": { "lint": "eslint .", - "test": "babel-tape-runner ./test/test-*.js | faucet" + "tape": "babel-tape-runner ./test/test-*.js | faucet", + "test": "parallelshell 'npm run lint' 'npm run tape'" }, "repository": { "type": "git", @@ -31,11 +32,15 @@ }, "homepage": "https://github.com/HubSpot/javascript", "devDependencies": { - "babel-tape-runner": "1.2.0", + "babel-plugin-transform-export-extensions": "^6.4.0", + "babel-plugin-transform-strict-mode": "^6.3.13", + "babel-preset-es2015": "^6.3.13", + "babel-tape-runner": "2.0.0", "eslint": "^1.10.3", - "eslint-plugin-react": "^3.14.0", + "eslint-plugin-react": "^3.16.0", "faucet": "0.0.1", - "react": "^0.13.3", + "parallelshell": "^2.0.0", + "react": "^0.14.6", "tape": "^4.2.2" }, "peerDependencies": { diff --git a/packages/eslint-config-hubspot/rules/.eslintrc.json b/packages/eslint-config-hubspot/rules/.eslintrc.json new file mode 100644 index 0000000000..de68aa25ca --- /dev/null +++ b/packages/eslint-config-hubspot/rules/.eslintrc.json @@ -0,0 +1,5 @@ +{ + "rules": { + "quote-props": 0 + } +} diff --git a/packages/eslint-config-hubspot/rules/best-practices.js b/packages/eslint-config-hubspot/rules/best-practices.js index 6bb1d759bf..32cd0c00aa 100644 --- a/packages/eslint-config-hubspot/rules/best-practices.js +++ b/packages/eslint-config-hubspot/rules/best-practices.js @@ -1,6 +1,6 @@ module.exports = { 'rules': { - // Enforces getter/setter pairs in objects + // enforces getter/setter pairs in objects 'accessor-pairs': 0, // treat var statements as if they were block scoped 'block-scoped-var': 2, @@ -13,7 +13,7 @@ module.exports = { // require default case in switch statements 'default-case': 2, // encourages use of dot notation whenever possible - 'dot-notation': [2, { 'allowKeywords': true}], + 'dot-notation': [2, { 'allowKeywords': true }], // enforces consistent newlines before or after dots 'dot-location': 0, // require the use of === and !== @@ -108,6 +108,7 @@ module.exports = { // requires to declare all vars on top of their containing scope 'vars-on-top': 2, // require immediate function invocation to be wrapped in parentheses + // http://eslint.org/docs/rules/wrap-iife.html 'wrap-iife': [2, 'any'], // require or disallow Yoda conditions 'yoda': 2 diff --git a/packages/eslint-config-hubspot/rules/es6.js b/packages/eslint-config-hubspot/rules/es6.js index 35d190d36b..63185ac1bc 100644 --- a/packages/eslint-config-hubspot/rules/es6.js +++ b/packages/eslint-config-hubspot/rules/es6.js @@ -23,6 +23,9 @@ module.exports = { 'experimentalObjectRestSpread': true }, 'rules': { + // enforces no braces where they can be omitted + // http://eslint.org/docs/rules/arrow-body-style + 'arrow-body-style': [2, 'as-needed'], // require parens in arrow function arguments 'arrow-parens': 0, // require space before/after arrow function's arrow @@ -43,12 +46,17 @@ module.exports = { // 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 arrow functions as callbacks + 'prefer-arrow-callback': 2, // 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, + // 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 } diff --git a/packages/eslint-config-hubspot/rules/react.js b/packages/eslint-config-hubspot/rules/react.js index 5bcd2e6543..f6c76b9837 100644 --- a/packages/eslint-config-hubspot/rules/react.js +++ b/packages/eslint-config-hubspot/rules/react.js @@ -10,19 +10,19 @@ 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, { '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']}], + '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, 'always'], // 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, {'selfClosing': 'tag-aligned', 'nonEmpty': 'after-props'}], + 'react/jsx-closing-bracket-location': [2, { 'selfClosing': 'tag-aligned', 'nonEmpty': false }], // 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}], + '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, { @@ -37,13 +37,13 @@ module.exports = { '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}], + '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}], + '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, @@ -76,7 +76,7 @@ module.exports = { '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': [0, {'react': '0.14.0'}], + 'react/no-deprecated': [0, { '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'], @@ -91,7 +91,7 @@ module.exports = { 'react/no-is-mounted': 0, // 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}], + '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, @@ -106,13 +106,13 @@ module.exports = { 'react/prefer-es6-class': [0, '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: []}], + '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']}], + '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, diff --git a/packages/eslint-config-hubspot/rules/style.js b/packages/eslint-config-hubspot/rules/style.js index 0ff1f157cf..8b8a1a272d 100644 --- a/packages/eslint-config-hubspot/rules/style.js +++ b/packages/eslint-config-hubspot/rules/style.js @@ -3,11 +3,11 @@ module.exports = { // enforce spacing inside array brackets 'array-bracket-spacing': [2, 'never'], // enforce one true brace style - 'brace-style': [2, '1tbs', {'allowSingleLine': true }], + 'brace-style': [2, '1tbs', { 'allowSingleLine': true }], // require camel case names - 'camelcase': [2, {'properties': 'never'}], + 'camelcase': [2, { 'properties': 'never' }], // enforce spacing before and after comma - 'comma-spacing': [2, {'before': false, 'after': true}], + 'comma-spacing': [2, { 'before': false, 'after': true }], // enforce one true comma style 'comma-style': [2, 'last'], // disallow padding inside computed properties @@ -20,7 +20,8 @@ module.exports = { '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.) + // 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 @@ -29,7 +30,7 @@ module.exports = { // 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}], + 'key-spacing': [2, { 'beforeColon': false, 'afterColon': true }], // enforces empty lines around comments 'lines-around-comment': 0, // disallow mixed 'LF' and 'CRLF' as linebreaks @@ -43,7 +44,7 @@ module.exports = { // specify the maximum depth callbacks can be nested 'max-nested-callbacks': 0, // require a capital letter for constructors - 'new-cap': [2, {'newIsCap': true, 'capIsNew': false}], + 'new-cap': [2, { 'newIsCap': true, 'capIsNew': false }], // disallow the omission of parentheses when invoking a constructor with no arguments 'new-parens': 0, // allow/disallow an empty newline after var statement @@ -59,7 +60,7 @@ module.exports = { // 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}], + 'no-multiple-empty-lines': [2, { 'max': 2, 'maxEOF': 1 }], // disallow nested ternary expressions 'no-nested-ternary': 2, // disallow use of the Object constructor @@ -92,7 +93,7 @@ module.exports = { // require identifiers to match the provided regular expression 'id-match': 0, // enforce spacing before and after semicolons - 'semi-spacing': [2, {'before': false, 'after': true}], + '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 diff --git a/packages/eslint-config-hubspot/rules/variables.js b/packages/eslint-config-hubspot/rules/variables.js index 3da93fe826..59914313f9 100644 --- a/packages/eslint-config-hubspot/rules/variables.js +++ b/packages/eslint-config-hubspot/rules/variables.js @@ -19,7 +19,7 @@ module.exports = { // 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'}], + '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/react/README.md b/react/README.md index 7be63b5591..f6710eef96 100644 --- a/react/README.md +++ b/react/README.md @@ -8,7 +8,7 @@ ## Table of Contents 1. [Basic Rules](#basic-rules) - 1. [Class vs `React.createClass`](#class-vs-reactcreateclass) + 1. [Class vs `React.createClass` vs stateless](#class-vs-reactcreateclass-vs-stateless) 1. [Naming](#naming) 1. [Declaration](#declaration) 1. [Alignment](#alignment) @@ -30,28 +30,47 @@ - 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` vs stateless - - Use `class extends React.Component` unless you have a very good reason to use mixins. + - If you have internal state and/or refs, prefer `class extends React.Component` over `React.createClass` unless you have a very good reason to use mixins. 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
; + return
{this.state.hello}
; } }); // good class Listing extends React.Component { + // ... render() { - return
; + return
{this.state.hello}
; } } ``` + And if you don't have state or refs, prefer functions over classes: + + ```javascript + + // bad + class Listing extends React.Component { + render() { + return
{this.props.hello}
; + } + } + + // good + function Listing({ hello }) { + return
{hello}
; + } + ``` + ## Naming - **Extensions**: Use `.jsx` extension for React components. @@ -123,12 +142,21 @@ // if props fit in one line then keep it on the same line - // children get indented normally + // children get indented normally with closing brackets either `after-props` + + // or `tag-aligned` + + + + ``` ## Quotes @@ -410,30 +438,32 @@ - How to define `propTypes`, `defaultProps`, `contextTypes`, etc... ```javascript - import React, { Component, PropTypes } from 'react'; + import React, { PropTypes } from 'react'; const propTypes = { - id: PropTypes.number.isRequired, - url: PropTypes.string.isRequired, - text: PropTypes.string, + id: PropTypes.number.isRequired, + url: PropTypes.string.isRequired, + text: PropTypes.string, }; const defaultProps = { - text: 'Hello World', + text: 'Hello World', }; - export default class Link extends Component { - static methodsAreOk() { + class Link extends React.Component { + static methodsAreOk() { return true; - } + } - render() { + render() { return {this.props.text} - } + } } Link.propTypes = propTypes; Link.defaultProps = defaultProps; + + export default Link; ``` From a16954ef92f70f0ad20bf921de63bd568696c275 Mon Sep 17 00:00:00 2001 From: Nick Hwang Date: Sun, 24 Jan 2016 16:15:49 -0500 Subject: [PATCH 34/54] Ignore arrow-body-style While I'm a fan of the rule, I would rather wait for the variant/option where you can have the block return statement on multiline. --- README.md | 5 +++++ package.json | 2 +- packages/eslint-config-hubspot/CHANGELOG.md | 4 ++++ packages/eslint-config-hubspot/package.json | 2 +- packages/eslint-config-hubspot/rules/es6.js | 2 +- 5 files changed, 12 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 2944055e31..7faa28b0b9 100644 --- a/README.md +++ b/README.md @@ -799,6 +799,11 @@ Other Style Guides (from Airbnb) const nextNumber = number + 1; return `A string containing the ${nextNumber}.`; }); + + // okay + [1, 2, 3].map(number => { + return `A string containing the ${number}.`; + }); ``` - [8.3](#8.3) In case the expression spans over multiple lines, wrap it in parentheses for better readability. diff --git a/package.json b/package.json index 9285577fc3..73d8b5846a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hubspot-style", - "version": "4.0.0", + "version": "4.0.1", "description": "HubSpot's version of a mostly reasonable approach to JavaScript", "scripts": { "difftool": "./bin/difftool", diff --git a/packages/eslint-config-hubspot/CHANGELOG.md b/packages/eslint-config-hubspot/CHANGELOG.md index 50a4e56b00..90636b980a 100644 --- a/packages/eslint-config-hubspot/CHANGELOG.md +++ b/packages/eslint-config-hubspot/CHANGELOG.md @@ -1,3 +1,7 @@ +4.0.1 / 2016-01-24 +================== +- [hubspot] Ignore `arrow-body-style` + 4.0.0 / 2016-01-22 ================== - [breaking] require outer IIFE wrapping; flesh out guide section diff --git a/packages/eslint-config-hubspot/package.json b/packages/eslint-config-hubspot/package.json index 927eee839a..a1cd2bd44a 100644 --- a/packages/eslint-config-hubspot/package.json +++ b/packages/eslint-config-hubspot/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-hubspot", - "version": "4.0.0", + "version": "4.0.1", "description": "HubSpot's ESLint config, following our styleguide", "main": "index.js", "scripts": { diff --git a/packages/eslint-config-hubspot/rules/es6.js b/packages/eslint-config-hubspot/rules/es6.js index 63185ac1bc..b8eb830e20 100644 --- a/packages/eslint-config-hubspot/rules/es6.js +++ b/packages/eslint-config-hubspot/rules/es6.js @@ -25,7 +25,7 @@ module.exports = { 'rules': { // enforces no braces where they can be omitted // http://eslint.org/docs/rules/arrow-body-style - 'arrow-body-style': [2, 'as-needed'], + 'arrow-body-style': [0, 'as-needed'], // require parens in arrow function arguments 'arrow-parens': 0, // require space before/after arrow function's arrow From c5d4a68baf42f2ba36a1825c12a7d4f9c249963b Mon Sep 17 00:00:00 2001 From: Nick Hwang Date: Tue, 26 Jan 2016 09:57:57 -0500 Subject: [PATCH 35/54] Add script for continuing difftool --- bin/difftool | 51 ++++++++++++++++++++++++++++++--------------------- package.json | 3 ++- 2 files changed, 32 insertions(+), 22 deletions(-) diff --git a/bin/difftool b/bin/difftool index c22e11aa82..4945ced916 100755 --- a/bin/difftool +++ b/bin/difftool @@ -30,32 +30,41 @@ function rename() { mv "$2" "$1" } -# Add Airbnb git remote -if [[ -z $(git remote -v | grep -e "$AIRBNB_REMOTE\s\+$AIRBNB_GIT\s\+(fetch)") ]]; then - git remote add "$AIRBNB_REMOTE" "$AIRBNB_GIT" -fi +function difftool() { + git difftool --prompt "$COMPARATE_BRANCH" +} -# Stash any existing changes before diffing -git stash save "$STASH_MESSAGE" +if [[ "$1" != "--continue" ]]; then + # Add Airbnb git remote + if [[ -z $(git remote -v | grep -e "$AIRBNB_REMOTE\s\+$AIRBNB_GIT\s\+(fetch)") ]]; then + git remote add "$AIRBNB_REMOTE" "$AIRBNB_GIT" + fi -# Checkout working branch -checkout "$WORKING_BRANCH" + # Stash any existing changes before diffing + git stash save "$STASH_MESSAGE" -# Fetch Airbnb changes -git fetch "$AIRBNB_REMOTE" "$REMOTE_BRANCH" + # Checkout working branch + checkout "$WORKING_BRANCH" -# Checkout Airbnb remote branch -checkout "$COMPARATE_BRANCH" "$AIRBNB_REMOTE/$REMOTE_BRANCH" + # Fetch Airbnb changes + git fetch "$AIRBNB_REMOTE" "$REMOTE_BRANCH" -# Rename eslint-config-airbnb to eslint-config-hubspot for diffing -rename "$ESLINT_HUBSPOT" "$ESLINT_AIRBNB" + # Checkout Airbnb remote branch + checkout "$COMPARATE_BRANCH" "$AIRBNB_REMOTE/$REMOTE_BRANCH" -# Commit rename for diffing -git add "$ESLINT_AIRBNB" "$ESLINT_HUBSPOT" -git commit -m "$COMMIT_MESSAGE" + # Rename eslint-config-airbnb to eslint-config-hubspot for diffing + rename "$ESLINT_HUBSPOT" "$ESLINT_AIRBNB" -# Checkout last branch to begin diffing -git checkout "$WORKING_BRANCH" + # Commit rename for diffing + git add "$ESLINT_AIRBNB" "$ESLINT_HUBSPOT" + git commit -m "$COMMIT_MESSAGE" -# Begin diffing -git difftool --prompt "$COMPARATE_BRANCH" + # Checkout last branch to begin diffing + git checkout "$WORKING_BRANCH" + + # Begin diffing + difftool +else + # Continue difftool + difftool +fi diff --git a/package.json b/package.json index 73d8b5846a..1124640b75 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,8 @@ "description": "HubSpot's version of a mostly reasonable approach to JavaScript", "scripts": { "difftool": "./bin/difftool", - "cleanup": "./bin/cleanup", + "difftool:continue": "./bin/difftool --continue", + "difftool:cleanup": "./bin/cleanup", "publish:config": "cd packages/eslint-config-hubspot && npm publish", "publish:all": "npm publish && npm run publish:config" }, From b9a9d951772f528df7998985c0816e44819d789f Mon Sep 17 00:00:00 2001 From: Nick Hwang Date: Tue, 26 Jan 2016 10:16:42 -0500 Subject: [PATCH 36/54] Update readmes --- README.md | 245 ++++++++++-------------------------------------- react/README.md | 54 ++++------- 2 files changed, 63 insertions(+), 236 deletions(-) diff --git a/README.md b/README.md index 7faa28b0b9..3359d43062 100644 --- a/README.md +++ b/README.md @@ -92,12 +92,10 @@ Other Style Guides (from Airbnb) ## References - - [2.1](#2.1) Use `const` for all of your references; avoid using `var`. + - [2.1](#2.1) Use `const` for all of your references; avoid using `var`. eslint: [`prefer-const`](http://eslint.org/docs/rules/prefer-const.html), [`no-const-assign`](http://eslint.org/docs/rules/no-const-assign.html) > 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 var a = 1; @@ -108,14 +106,10 @@ Other Style Guides (from Airbnb) const b = 2; ``` - - [2.2](#2.2) If you must reassign references, use `let` instead of `var`. + - [2.2](#2.2) If you must reassign references, use `let` instead of `var`. eslint: [`no-var`](http://eslint.org/docs/rules/no-var.html) jscs: [`disallowVar`](http://jscs.info/rule/disallowVar) > Why? `let` is block-scoped rather than function-scoped like `var`. - eslint rules: [`no-var`](http://eslint.org/docs/rules/no-var.html). - - jscs rules: [`disallowVar`](http://jscs.info/rule/disallowVar). - ```javascript // bad var count = 1; @@ -146,9 +140,7 @@ Other Style Guides (from Airbnb) ## Objects - - [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). + - [3.1](#3.1) Use the literal syntax for object creation. eslint: [`no-new-object`](http://eslint.org/docs/rules/no-new-object.html) ```javascript // bad @@ -158,9 +150,7 @@ Other Style Guides (from Airbnb) const item = {}; ``` - - [3.2](#3.2) If your code will be executed in browsers in script context, don't use [reserved words](http://es5.github.io/#x7.6.1) as keys. It won't work in IE8. [More info](https://github.com/airbnb/javascript/issues/61). It’s OK to use them in ES6 modules and server-side code. - - jscs rules: [`disallowIdentiferNames`](http://jscs.info/rule/disallowIdentifierNames). + - [3.2](#3.2) If your code will be executed in browsers in script context, don't use [reserved words](http://es5.github.io/#x7.6.1) as keys. It won't work in IE8. [More info](https://github.com/airbnb/javascript/issues/61). It’s OK to use them in ES6 modules and server-side code. jscs: [`disallowIdentiferNames`](http://jscs.info/rule/disallowIdentifierNames) ```javascript // bad @@ -176,9 +166,7 @@ Other Style Guides (from Airbnb) }; ``` - - [3.3](#3.3) Use readable synonyms in place of reserved words. - - jscs rules: [`disallowIdentiferNames`](http://jscs.info/rule/disallowIdentifierNames). + - [3.3](#3.3) Use readable synonyms in place of reserved words. jscs: [`disallowIdentiferNames`](http://jscs.info/rule/disallowIdentifierNames) ```javascript // bad @@ -224,11 +212,7 @@ Other Style Guides (from Airbnb) ``` - - [3.5](#3.5) Use object method shorthand. - - eslint rules: [`object-shorthand`](http://eslint.org/docs/rules/object-shorthand.html). - - jscs rules: [`requireEnhancedObjectLiterals`](http://jscs.info/rule/requireEnhancedObjectLiterals). + - [3.5](#3.5) Use object method shorthand. eslint: [`object-shorthand`](http://eslint.org/docs/rules/object-shorthand.html) jscs: [`requireEnhancedObjectLiterals`](http://jscs.info/rule/requireEnhancedObjectLiterals) ```javascript // bad @@ -251,14 +235,10 @@ Other Style Guides (from Airbnb) ``` - - [3.6](#3.6) Use property value shorthand. + - [3.6](#3.6) Use property value shorthand. eslint: [`object-shorthand`](http://eslint.org/docs/rules/object-shorthand.html) jscs: [`requireEnhancedObjectLiterals`](http://jscs.info/rule/requireEnhancedObjectLiterals) > Why? It is shorter to write and descriptive. - eslint rules: [`object-shorthand`](http://eslint.org/docs/rules/object-shorthand.html). - - jscs rules: [`requireEnhancedObjectLiterals`](http://jscs.info/rule/requireEnhancedObjectLiterals). - ```javascript const lukeSkywalker = 'Luke Skywalker'; @@ -302,14 +282,10 @@ Other Style Guides (from Airbnb) }; ``` - - [3.8](#3.8) Only quote properties that are invalid identifiers. + - [3.8](#3.8) Only quote properties that are invalid identifiers. eslint: [`quote-props`](http://eslint.org/docs/rules/quote-props.html) jscs: [`disallowQuotedKeysInObjects`](http://jscs.info/rule/disallowQuotedKeysInObjects) > 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). - - jscs rules: [`disallowQuotedKeysInObjects`](http://jscs.info/rule/disallowQuotedKeysInObjects). - ```javascript // bad const bad = { @@ -346,9 +322,7 @@ Other Style Guides (from Airbnb) ## 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). + - [4.1](#4.1) Use the literal syntax for array creation. eslint: [`no-array-constructor`](http://eslint.org/docs/rules/no-array-constructor.html) ```javascript // bad @@ -397,12 +371,10 @@ Other Style Guides (from Airbnb) ## Destructuring - - [5.1](#5.1) Use object destructuring when accessing and using multiple properties of an object. + - [5.1](#5.1) Use object destructuring when accessing and using multiple properties of an object. jscs: [`requireObjectDestructuring`](http://jscs.info/rule/requireObjectDestructuring) > Why? Destructuring saves you from creating temporary references for those properties. - jscs rules: [`requireObjectDestructuring`](http://jscs.info/rule/requireObjectDestructuring). - ```javascript // bad function getFullName(user) { @@ -424,9 +396,7 @@ Other Style Guides (from Airbnb) } ``` - - [5.2](#5.2) Use array destructuring. - - jscs rules: [`requireArrayDestructuring`](http://jscs.info/rule/requireArrayDestructuring). + - [5.2](#5.2) Use array destructuring. jscs: [`requireArrayDestructuring`](http://jscs.info/rule/requireArrayDestructuring) ```javascript const arr = [1, 2, 3, 4]; @@ -468,11 +438,7 @@ Other Style Guides (from Airbnb) ## Strings - - [6.1](#6.1) Use single quotes `''` for strings. - - eslint rules: [`quotes`](http://eslint.org/docs/rules/quotes.html). - - jscs rules: [`validateQuoteMarks`](http://jscs.info/rule/validateQuoteMarks). + - [6.1](#6.1) Use single quotes `''` for strings. eslint: [`quotes`](http://eslint.org/docs/rules/quotes.html) jscs: [`validateQuoteMarks`](http://jscs.info/rule/validateQuoteMarks) ```javascript // bad @@ -502,14 +468,10 @@ Other Style Guides (from Airbnb) ``` - - [6.4](#6.4) When programmatically building up strings, use template strings instead of concatenation. + - [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) > 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). - - jscs rules: [`requireTemplateStrings`](http://jscs.info/rule/requireTemplateStrings). - ```javascript // bad function sayHi(name) { @@ -533,12 +495,10 @@ Other Style Guides (from Airbnb) ## Functions - - [7.1](#7.1) Use function declarations instead of function expressions. + - [7.1](#7.1) Use function declarations instead of function expressions. jscs: [`requireFunctionDeclarations`](http://jscs.info/rule/requireFunctionDeclarations) > 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. - jscs rules: [`requireFunctionDeclarations`](http://jscs.info/rule/requireFunctionDeclarations). - ```javascript // bad const foo = function () { @@ -549,14 +509,10 @@ Other Style Guides (from Airbnb) } ``` - - [7.2](#7.2) Immediately invoked function expressions: + - [7.2](#7.2) Immediately invoked function expressions: eslint: [`wrap-iife`](http://eslint.org/docs/rules/wrap-iife.html) jscs: [`requireParenthesesAroundIIFE`](http://jscs.info/rule/requireParenthesesAroundIIFE) > Why? An immediately invoked function expression is a single unit - wrapping both it, and its invocation parens, in parens, cleanly expresses this. Note that in a world with modules everywhere, you almost never need an IIFE. - eslint rules: [`wrap-iife`](http://eslint.org/docs/rules/wrap-iife.html). - - jscs rules: [`requireParenthesesAroundIIFE`](http://jscs.info/rule/requireParenthesesAroundIIFE). - ```javascript // immediately-invoked function expression (IIFE) (function () { @@ -564,9 +520,7 @@ Other Style Guides (from Airbnb) }()); ``` - - [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. - - eslint rules: [`no-loop-func`](http://eslint.org/docs/rules/no-loop-func.html). + - [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. eslint: [`no-loop-func`](http://eslint.org/docs/rules/no-loop-func.html) - [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). @@ -703,12 +657,10 @@ Other Style Guides (from Airbnb) const y = function a() {}; ``` - - [7.12](#7.12) Never mutate parameters. + - [7.12](#7.12) Never mutate parameters. eslint: [`no-param-reassign`](http://eslint.org/docs/rules/no-param-reassign.html) > 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) { @@ -721,12 +673,10 @@ Other Style Guides (from Airbnb) }; ``` - - [7.13](#7.13) Never reassign parameters. + - [7.13](#7.13) Never reassign parameters. eslint: [`no-param-reassign`](http://eslint.org/docs/rules/no-param-reassign.html) > 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) { @@ -750,15 +700,11 @@ Other Style Guides (from Airbnb) ## Arrow Functions - - [8.1](#8.1) When you must use function expressions (as when passing an anonymous function), use arrow function notation. + - [8.1](#8.1) When you must use function expressions (as when passing an anonymous function), use arrow function notation. eslint: [`prefer-arrow-callback`](http://eslint.org/docs/rules/prefer-arrow-callback.html), [`arrow-spacing`](http://eslint.org/docs/rules/arrow-spacing.html) jscs: [`requireArrowFunctions`](http://jscs.info/rule/requireArrowFunctions) > 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. - - eslint rules: [`prefer-arrow-callback`](http://eslint.org/docs/rules/prefer-arrow-callback.html), [`arrow-spacing`](http://eslint.org/docs/rules/arrow-spacing.html). - - jscs rules: [`requireArrowFunctions`](http://jscs.info/rule/requireArrowFunctions). + > Why not? If you have a fairly complicated function, you might move that logic out into its own function declaration.. ```javascript // bad @@ -774,16 +720,12 @@ Other Style Guides (from Airbnb) }); ``` - - [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. + - [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. eslint: [`arrow-parens`](http://eslint.org/docs/rules/arrow-parens.html), [`arrow-body-style`](http://eslint.org/docs/rules/arrow-body-style.html) jscs: [`disallowParenthesesAroundArrowParam`](http://jscs.info/rule/disallowParenthesesAroundArrowParam), [`requireShorthandArrowFunctions`](http://jscs.info/rule/requireShorthandArrowFunctions) > Why? Syntactic sugar. It reads well when multiple functions are chained together. > 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). - - jscs rules: [`disallowParenthesesAroundArrowParam`](http://jscs.info/rule/disallowParenthesesAroundArrowParam), [`requireShorthandArrowFunctions`](http://jscs.info/rule/requireShorthandArrowFunctions). - ```javascript // good [1, 2, 3].map(number => `A string containing the ${number}.`); @@ -799,11 +741,6 @@ Other Style Guides (from Airbnb) const nextNumber = number + 1; return `A string containing the ${nextNumber}.`; }); - - // okay - [1, 2, 3].map(number => { - return `A string containing the ${number}.`; - }); ``` - [8.3](#8.3) In case the expression spans over multiple lines, wrap it in parentheses for better readability. @@ -825,14 +762,10 @@ Other Style Guides (from Airbnb) ``` - - [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. + - [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. eslint: [`arrow-parens`](http://eslint.org/docs/rules/arrow-parens.html) jscs: [`disallowParenthesesAroundArrowParam`](http://jscs.info/rule/disallowParenthesesAroundArrowParam) > Why? Less visual clutter. - eslint rules: [`arrow-parens`](http://eslint.org/docs/rules/arrow-parens.html). - - jscs rules: [`disallowParenthesesAroundArrowParam`](http://jscs.info/rule/disallowParenthesesAroundArrowParam). - ```js // bad [1, 2, 3].map((x) => x * x); @@ -1025,12 +958,10 @@ Other Style Guides (from Airbnb) ## Iterators and Generators - - [11.1](#11.1) Don't use iterators. Prefer JavaScript's higher-order functions like `map()` and `reduce()` instead of loops like `for-of`. + - [11.1](#11.1) Don't use iterators. Prefer JavaScript's higher-order functions like `map()` and `reduce()` instead of loops like `for-of`. eslint: [`no-iterator`](http://eslint.org/docs/rules/no-iterator.html) > 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]; @@ -1061,11 +992,7 @@ Other Style Guides (from Airbnb) ## Properties - - [12.1](#12.1) Use dot notation when accessing properties. - - eslint rules: [`dot-notation`](http://eslint.org/docs/rules/dot-notation.html). - - jscs rules: [`requireDotNotation`](http://jscs.info/rule/requireDotNotation). + - [12.1](#12.1) Use dot notation when accessing properties. eslint: [`dot-notation`](http://eslint.org/docs/rules/dot-notation.html) jscs: [`requireDotNotation`](http://jscs.info/rule/requireDotNotation) ```javascript const luke = { @@ -1110,14 +1037,10 @@ Other Style Guides (from Airbnb) const superPower = new SuperPower(); ``` - - [13.2](#13.2) Use one `const` declaration per variable. + - [13.2](#13.2) Use one `const` declaration per variable. eslint: [`one-var`](http://eslint.org/docs/rules/one-var.html) jscs: [`disallowMultipleVarDecl`](http://jscs.info/rule/disallowMultipleVarDecl) > 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). - - jscs rules: [`disallowMultipleVarDecl`](http://jscs.info/rule/disallowMultipleVarDecl). - ```javascript // bad const items = getItems(), @@ -1300,12 +1223,10 @@ Other Style Guides (from Airbnb) ## Comparison Operators & Equality - - [15.1](#15.1) Use `===` and `!==` over `==` and `!=`. + - [15.1](#15.1) Use `===` and `!==` over `==` and `!=`. eslint: [`eqeqeq`](http://eslint.org/docs/rules/eqeqeq.html) - [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** @@ -1376,11 +1297,7 @@ Other Style Guides (from Airbnb) ``` - [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). - - jscs rules: [`disallowNewlineBeforeBlockStatements`](http://jscs.info/rule/disallowNewlineBeforeBlockStatements). + `if` block's closing brace. eslint: [`brace-style`](http://eslint.org/docs/rules/brace-style.html) jscs: [`disallowNewlineBeforeBlockStatements`](http://jscs.info/rule/disallowNewlineBeforeBlockStatements) ```javascript // bad @@ -1510,11 +1427,7 @@ Other Style Guides (from Airbnb) ## Whitespace - - [18.1](#18.1) Use soft tabs set to 2 spaces. - - eslint rules: [`indent`](http://eslint.org/docs/rules/indent.html). - - jscs rules: [`validateIndentation`](http://jscs.info/rule/validateIndentation). + - [18.1](#18.1) Use soft tabs set to 2 spaces. eslint: [`indent`](http://eslint.org/docs/rules/indent.html) jscs: [`validateIndentation`](http://jscs.info/rule/validateIndentation) ```javascript // bad @@ -1533,11 +1446,7 @@ Other Style Guides (from Airbnb) } ``` - - [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). - - jscs rules: [`requireSpaceBeforeBlockStatements`](http://jscs.info/rule/requireSpaceBeforeBlockStatements). + - [18.2](#18.2) Place 1 space before the leading brace. eslint: [`space-before-blocks`](http://eslint.org/docs/rules/space-before-blocks.html) jscs: [`requireSpaceBeforeBlockStatements`](http://jscs.info/rule/requireSpaceBeforeBlockStatements) ```javascript // bad @@ -1563,11 +1472,7 @@ Other Style Guides (from Airbnb) }); ``` - - [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). - - jscs rules: [`requireSpaceAfterKeywords`](http://jscs.info/rule/requireSpaceAfterKeywords). + - [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: [`space-after-keywords`](http://eslint.org/docs/rules/space-after-keywords.html), [`space-before-keywords`](http://eslint.org/docs/rules/space-before-keywords.html) jscs: [`requireSpaceAfterKeywords`](http://jscs.info/rule/requireSpaceAfterKeywords) ```javascript // bad @@ -1591,11 +1496,7 @@ Other Style Guides (from Airbnb) } ``` - - [18.4](#18.4) Set off operators with spaces. - - eslint rules: [`space-infix-ops`](http://eslint.org/docs/rules/space-infix-ops.html). - - jscs rules: [`requireSpaceBeforeBinaryOperators`](http://jscs.info/rule/requireSpaceBeforeBinaryOperators), [`requireSpaceAfterBinaryOperators`](http://jscs.info/rule/requireSpaceAfterBinaryOperators). + - [18.4](#18.4) Set off operators with spaces. eslint: [`space-infix-ops`](http://eslint.org/docs/rules/space-infix-ops.html) jscs: [`requireSpaceBeforeBinaryOperators`](http://jscs.info/rule/requireSpaceBeforeBinaryOperators), [`requireSpaceAfterBinaryOperators`](http://jscs.info/rule/requireSpaceAfterBinaryOperators) ```javascript // bad @@ -1669,9 +1570,7 @@ Other Style Guides (from Airbnb) .call(tron.led); ``` - - [18.7](#18.7) Leave a blank line after blocks and before the next statement. - - jscs rules: [`requirePaddingNewLinesAfterBlocks`](http://jscs.info/rule/requirePaddingNewLinesAfterBlocks). + - [18.7](#18.7) Leave a blank line after blocks and before the next statement. jscs: [`requirePaddingNewLinesAfterBlocks`](http://jscs.info/rule/requirePaddingNewLinesAfterBlocks) ```javascript // bad @@ -1728,11 +1627,7 @@ Other Style Guides (from Airbnb) 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). - - jscs rules: [`disallowPaddingNewlinesInBlocks`](http://jscs.info/rule/disallowPaddingNewlinesInBlocks). + - [18.8](#18.8) Do not pad your blocks with blank lines. eslint: [`padded-blocks`](http://eslint.org/docs/rules/padded-blocks.html) jscs: [`disallowPaddingNewlinesInBlocks`](http://jscs.info/rule/disallowPaddingNewlinesInBlocks) ```javascript // bad @@ -1764,11 +1659,7 @@ Other Style Guides (from Airbnb) } ``` - - [18.9](#18.9) Do not add spaces inside parentheses. - - eslint rules: [`space-in-parens`](http://eslint.org/docs/rules/space-in-parens.html). - - jscs rules: [`disallowSpacesInsideParentheses`](http://jscs.info/rule/disallowSpacesInsideParentheses). + - [18.9](#18.9) Do not add spaces inside parentheses. eslint: [`space-in-parens`](http://eslint.org/docs/rules/space-in-parens.html) jscs: [`disallowSpacesInsideParentheses`](http://jscs.info/rule/disallowSpacesInsideParentheses) ```javascript // bad @@ -1792,11 +1683,7 @@ Other Style Guides (from Airbnb) } ``` - - [18.10](#18.10) Do not add spaces inside brackets. - - eslint rules: [`array-bracket-spacing`](http://eslint.org/docs/rules/array-bracket-spacing.html). - - jscs rules: [`disallowSpacesInsideArrayBrackets`](http://jscs.info/rule/disallowSpacesInsideArrayBrackets). + - [18.10](#18.10) Do not add spaces inside brackets. eslint: [`array-bracket-spacing`](http://eslint.org/docs/rules/array-bracket-spacing.html) jscs: [`disallowSpacesInsideArrayBrackets`](http://jscs.info/rule/disallowSpacesInsideArrayBrackets) ```javascript // bad @@ -1808,11 +1695,7 @@ Other Style Guides (from Airbnb) 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). - - jscs rules: [`disallowSpacesInsideObjectBrackets`](http://jscs.info/rule/disallowSpacesInsideObjectBrackets). + - [18.11](#18.11) Add spaces inside curly braces. eslint: [`object-curly-spacing`](http://eslint.org/docs/rules/object-curly-spacing.html) jscs: [`disallowSpacesInsideObjectBrackets`](http://jscs.info/rule/disallowSpacesInsideObjectBrackets) ```javascript // bad @@ -1822,14 +1705,10 @@ Other Style Guides (from Airbnb) const foo = { clark: 'kent' }; ``` - - [18.12](#18.12) Avoid having lines of code that are longer than 100 characters (including whitespace). + - [18.12](#18.12) Avoid having lines of code that are longer than 100 characters (including whitespace). eslint: [`max-len`](http://eslint.org/docs/rules/max-len.html) jscs: [`maximumLineLength`](http://jscs.info/rule/maximumLineLength) > Why? This ensures readability and maintainability. - eslint rules: [`max-len`](http://eslint.org/docs/rules/max-len.html). - - jscs rules: [`maximumLineLength`](http://jscs.info/rule/maximumLineLength). - ```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!'; @@ -1855,11 +1734,7 @@ Other Style Guides (from Airbnb) ## Commas - - [19.1](#19.1) Leading commas: **Nope.** - - eslint rules: [`comma-style`](http://eslint.org/docs/rules/comma-style.html). - - jscs rules: [`requireCommaBeforeLineBreak`](http://jscs.info/rule/requireCommaBeforeLineBreak). + - [19.1](#19.1) Leading commas: **Nope.** eslint: [`comma-style`](http://eslint.org/docs/rules/comma-style.html) jscs: [`requireCommaBeforeLineBreak`](http://jscs.info/rule/requireCommaBeforeLineBreak) ```javascript // bad @@ -1893,11 +1768,7 @@ Other Style Guides (from Airbnb) }; ``` - - [19.2](#19.2) Additional trailing comma: **Yup.** - - eslint rules: [`comma-dangle`](http://eslint.org/docs/rules/comma-dangle.html). - - jscs rules: [`requireTrailingComma`](http://jscs.info/rule/requireTrailingComma). + - [19.2](#19.2) Additional trailing comma: **Yup.** eslint: [`comma-dangle`](http://eslint.org/docs/rules/comma-dangle.html) jscs: [`requireTrailingComma`](http://jscs.info/rule/requireTrailingComma) > 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. @@ -1945,11 +1816,7 @@ Other Style Guides (from Airbnb) ## Semicolons - - [20.1](#20.1) **Yup.** - - eslint rules: [`semi`](http://eslint.org/docs/rules/semi.html). - - jscs rules: [`requireSemicolons`](http://jscs.info/rule/requireSemicolons). + - [20.1](#20.1) **Yup.** eslint: [`semi`](http://eslint.org/docs/rules/semi.html) jscs: [`requireSemicolons`](http://jscs.info/rule/requireSemicolons) ```javascript // bad @@ -1991,9 +1858,7 @@ Other Style Guides (from Airbnb) const totalScore = String(this.reviewScore); ``` - - [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). + - [21.3](#21.3) Numbers: Use `Number` for type casting and `parseInt` always with a radix for parsing strings. eslint: [`radix`](http://eslint.org/docs/rules/radix) ```javascript const inputValue = '4'; @@ -2029,7 +1894,7 @@ Other Style Guides (from Airbnb) const val = inputValue >> 0; ``` - - [21.5](#21.5) **Note:** Be careful when using bitshift operations. Numbers are represented as [64-bit values](http://es5.github.io/#x4.3.19), but Bitshift operations always return a 32-bit integer ([source](http://es5.github.io/#x11.7)). Bitshift can lead to unexpected behavior for integer values larger than 32 bits. [Discussion](https://github.com/airbnb/javascript/issues/109). Largest signed 32-bit Int is 2,147,483,647: + - [21.5](#21.5) **Note:** Be careful when using bitshift operations. Numbers are represented as [64-bit values](http://es5.github.io/#x4.3.19), but bitshift operations always return a 32-bit integer ([source](http://es5.github.io/#x11.7)). Bitshift can lead to unexpected behavior for integer values larger than 32 bits. [Discussion](https://github.com/airbnb/javascript/issues/109). Largest signed 32-bit Int is 2,147,483,647: ```javascript 2147483647 >> 0 //=> 2147483647 @@ -2071,11 +1936,7 @@ Other Style Guides (from Airbnb) } ``` - - [22.2](#22.2) Use camelCase when naming objects, functions, and instances. - - eslint rules: [`camelcase`](http://eslint.org/docs/rules/camelcase.html). - - jscs rules: [`requireCamelCaseOrUpperCaseIdentifiers`](http://jscs.info/rule/requireCamelCaseOrUpperCaseIdentifiers). + - [22.2](#22.2) Use camelCase when naming objects, functions, and instances. eslint: [`camelcase`](http://eslint.org/docs/rules/camelcase.html) jscs: [`requireCamelCaseOrUpperCaseIdentifiers`](http://jscs.info/rule/requireCamelCaseOrUpperCaseIdentifiers) ```javascript // bad @@ -2088,11 +1949,7 @@ Other Style Guides (from Airbnb) function thisIsMyFunction() {} ``` - - [22.3](#22.3) Use PascalCase when naming constructors or classes. - - eslint rules: [`new-cap`](http://eslint.org/docs/rules/new-cap.html). - - jscs rules: [`requireCapitalizedConstructors`](http://jscs.info/rule/requireCapitalizedConstructors). + - [22.3](#22.3) Use PascalCase when naming constructors or classes. eslint: [`new-cap`](http://eslint.org/docs/rules/new-cap.html) jscs: [`requireCapitalizedConstructors`](http://jscs.info/rule/requireCapitalizedConstructors) ```javascript // bad @@ -2116,11 +1973,7 @@ Other Style Guides (from Airbnb) }); ``` - - [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). - - jscs rules: [`disallowDanglingUnderscores`](http://jscs.info/rule/disallowDanglingUnderscores). + - [22.4](#22.4) Use a leading underscore `_` when naming private properties. eslint: [`no-underscore-dangle`](http://eslint.org/docs/rules/no-underscore-dangle.html) jscs: [`disallowDanglingUnderscores`](http://jscs.info/rule/disallowDanglingUnderscores) ```javascript // bad @@ -2131,9 +1984,7 @@ Other Style Guides (from Airbnb) this._firstName = 'Panda'; ``` - - [22.5](#22.5) Don't save references to `this`. Use arrow functions or Function#bind. - - jscs rules: [`disallowNodeTypes`](http://jscs.info/rule/disallowNodeTypes). + - [22.5](#22.5) Don't save references to `this`. Use arrow functions or Function#bind. jscs: [`disallowNodeTypes`](http://jscs.info/rule/disallowNodeTypes) ```javascript // bad @@ -2292,9 +2143,7 @@ Other Style Guides (from Airbnb) ## jQuery - - [25.1](#25.1) Prefix jQuery object variables with a `$`. - - jscs rules: [`requireDollarBeforejQueryAssignment`](http://jscs.info/rule/requireDollarBeforejQueryAssignment). + - [25.1](#25.1) Prefix jQuery object variables with a `$`. jscs: [`requireDollarBeforejQueryAssignment`](http://jscs.info/rule/requireDollarBeforejQueryAssignment) ```javascript // bad diff --git a/react/README.md b/react/README.md index f6710eef96..5d22146bbf 100644 --- a/react/README.md +++ b/react/README.md @@ -26,15 +26,13 @@ ## 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). + - However, multiple [Stateless, or Pure, Components](https://facebook.github.io/react/docs/reusable-components.html#stateless-functions) are allowed per file. eslint: [`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` vs stateless - - If you have internal state and/or refs, prefer `class extends React.Component` over `React.createClass` unless you have a very good reason to use mixins. - - eslint rules: [`react/prefer-es6-class`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/prefer-es6-class.md). + - If you have internal state and/or refs, prefer `class extends React.Component` over `React.createClass` unless you have a very good reason to use mixins. eslint: [`react/prefer-es6-class`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/prefer-es6-class.md) ```javascript // bad @@ -75,9 +73,7 @@ - **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. - - eslint rules: [`react/jsx-pascal-case`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-pascal-case.md). + - **Reference Naming**: Use PascalCase for React components and camelCase for their instances. eslint: [`react/jsx-pascal-case`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-pascal-case.md) ```javascript // bad @@ -124,9 +120,7 @@ ## 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). + - Follow these alignment styles for JSX syntax. eslint: [`react/jsx-closing-bracket-location`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-closing-bracket-location.md) ```javascript // bad @@ -161,12 +155,10 @@ ## Quotes - - Always use double quotes (`"`) for JSX attributes, but single quotes for all other JS. + - Always use double quotes (`"`) for JSX attributes, but single quotes for all other JS. eslint: [`jsx-quotes`](http://eslint.org/docs/rules/jsx-quotes) - > 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). + > 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. ```javascript // bad @@ -222,9 +214,7 @@ /> ``` - - Use explicit values for Boolean props - - eslint rules: [`react/jsx-boolean-value`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-boolean-value.md). + - Use explicit values for Boolean props. eslint: [`react/jsx-boolean-value`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-boolean-value.md) ```javascript // bad (implicit true) @@ -297,9 +287,7 @@ ## Parentheses - - 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). + - Wrap JSX tags in parentheses when they span more than one line. eslint: [`react/wrap-multilines`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/wrap-multilines.md) ```javascript // bad @@ -327,9 +315,7 @@ ## 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). + - Always self-close tags that have no children. eslint: [`react/self-closing-comp`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/self-closing-comp.md) ```javascript // bad @@ -339,9 +325,7 @@ ``` - - 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). + - If your component has multi-line properties, close its tag on a new line. eslint: [`react/jsx-closing-bracket-location`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-closing-bracket-location.md) ```javascript // bad @@ -358,11 +342,9 @@ ## Methods - - Bind event handlers for the render method in the constructor. - - > Why? A bind call in a the render path creates a brand new function on every single render. + - Bind event handlers for the render method in the constructor. eslint: [`react/jsx-no-bind`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-bind.md) - eslint rules: [`react/jsx-no-bind`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-bind.md). + > Why? A bind call in the render path creates a brand new function on every single render. ```javascript // bad @@ -434,7 +416,6 @@ 1. Optional render methods like `renderNavigation()` or `renderProfilePicture()` 1. `render` - - How to define `propTypes`, `defaultProps`, `contextTypes`, etc... ```javascript @@ -466,8 +447,7 @@ export default Link; ``` - - - Ordering for `React.createClass`: + - Ordering for `React.createClass`: eslint: [`react/sort-comp`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/sort-comp.md) 1. `displayName` 1. `mixins` @@ -478,7 +458,6 @@ 1. `defaultProps` 1. `getDefaultProps` 1. `getInitialState` - 1. `state` 1. `getChildContext` 1. `componentWillMount` 1. `componentDidMount` @@ -489,13 +468,12 @@ 1. `componentWillUnmount` 1. Getters, setters, event handlers, helper methods, etc. 1. Optional render methods like `renderNavigation()` or `renderProfilePicture()` - 1. render + 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`. + - Do not use `isMounted`. eslint: [`react/no-is-mounted`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-is-mounted.md) > Why? [`isMounted` is an anti-pattern][anti-pattern], is not available when using ES6 classes, and is on its way to being officially deprecated. From 8dc6bb6eee2cb110a0fcd30d3cb5b82582f04cb0 Mon Sep 17 00:00:00 2001 From: Rodolfo Carvalho Date: Fri, 29 Jan 2016 10:05:04 -0500 Subject: [PATCH 37/54] Allow usage of `==` when comparing to `null` I think this is an acceptable use case since most of the time `null` and `undefined` are semantically equivalent. --- packages/eslint-config-hubspot/rules/best-practices.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/eslint-config-hubspot/rules/best-practices.js b/packages/eslint-config-hubspot/rules/best-practices.js index 32cd0c00aa..4da3824d55 100644 --- a/packages/eslint-config-hubspot/rules/best-practices.js +++ b/packages/eslint-config-hubspot/rules/best-practices.js @@ -16,8 +16,8 @@ module.exports = { 'dot-notation': [2, { 'allowKeywords': true }], // enforces consistent newlines before or after dots 'dot-location': 0, - // require the use of === and !== - 'eqeqeq': 2, + // require the use of === and !==, except when comparing to null + 'eqeqeq': [2, "allow-null"], // make sure for-in loops have an if statement 'guard-for-in': 2, // disallow the use of alert, confirm, and prompt From a6e988a8da2f56dc3de2b5aee6f8344dfc3ead17 Mon Sep 17 00:00:00 2001 From: Nick Hwang Date: Fri, 29 Jan 2016 10:46:30 -0500 Subject: [PATCH 38/54] Update with airbnb/master --- README.md | 22 ++++++++++----------- packages/eslint-config-hubspot/CHANGELOG.md | 2 +- packages/eslint-config-hubspot/package.json | 6 +++--- react/README.md | 9 +++++++-- 4 files changed, 22 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 3359d43062..f891c93b71 100644 --- a/README.md +++ b/README.md @@ -1237,7 +1237,7 @@ Other Style Guides (from Airbnb) ```javascript if ([0] && []) { // true - // An array (even an empty one) is an object, objects will evaluate to true + // an array (even an empty one) is an object, objects will evaluate to true } ``` @@ -1288,10 +1288,10 @@ Other Style Guides (from Airbnb) } // bad - function () { return false; } + function foo() { return false; } // good - function () { + function bar() { return false; } ``` @@ -1431,17 +1431,17 @@ Other Style Guides (from Airbnb) ```javascript // bad - function () { + function foo() { ∙∙∙∙const name; } // bad - function () { + function bar() { ∙const name; } // good - function () { + function baz() { ∙∙const name; } ``` @@ -1849,7 +1849,7 @@ Other Style Guides (from Airbnb) - [21.2](#21.2) Strings: ```javascript - // => this.reviewScore = 9; + // => this.reviewScore = 9; // bad const totalScore = this.reviewScore + ''; @@ -2120,7 +2120,7 @@ Other Style Guides (from Airbnb) ... - $(this).on('listingUpdated', function (e, listingId) { + $(this).on('listingUpdated', (e, listingId) => { // do something with listingId }); ``` @@ -2133,7 +2133,7 @@ Other Style Guides (from Airbnb) ... - $(this).on('listingUpdated', function (e, data) { + $(this).on('listingUpdated', (e, data) => { // do something with data.listingId }); ``` @@ -2214,7 +2214,7 @@ Other Style Guides (from Airbnb) ## ECMAScript 6 Styles - - [27.1](#27.1) This is a collection of links to the various es6 features. + - [27.1](#27.1) This is a collection of links to the various ES6 features. 1. [Arrow Functions](#arrow-functions) 1. [Classes](#constructors) @@ -2237,7 +2237,7 @@ Other Style Guides (from Airbnb) - [28.1](#28.1) **Yup.** ```javascript - function () { + function foo() { return true; } ``` diff --git a/packages/eslint-config-hubspot/CHANGELOG.md b/packages/eslint-config-hubspot/CHANGELOG.md index 90636b980a..cceed1efba 100644 --- a/packages/eslint-config-hubspot/CHANGELOG.md +++ b/packages/eslint-config-hubspot/CHANGELOG.md @@ -1,6 +1,6 @@ 4.0.1 / 2016-01-24 ================== -- [hubspot] Ignore `arrow-body-style` + - [hubspot] Ignore `arrow-body-style` 4.0.0 / 2016-01-22 ================== diff --git a/packages/eslint-config-hubspot/package.json b/packages/eslint-config-hubspot/package.json index a1cd2bd44a..cfda82a127 100644 --- a/packages/eslint-config-hubspot/package.json +++ b/packages/eslint-config-hubspot/package.json @@ -37,11 +37,11 @@ "babel-preset-es2015": "^6.3.13", "babel-tape-runner": "2.0.0", "eslint": "^1.10.3", - "eslint-plugin-react": "^3.16.0", + "eslint-plugin-react": "^3.16.1", "faucet": "0.0.1", "parallelshell": "^2.0.0", - "react": "^0.14.6", - "tape": "^4.2.2" + "react": "^0.14.7", + "tape": "^4.4.0" }, "peerDependencies": { "eslint": "^1.0.0", diff --git a/react/README.md b/react/README.md index 5d22146bbf..e371d21867 100644 --- a/react/README.md +++ b/react/README.md @@ -52,7 +52,7 @@ } ``` - And if you don't have state or refs, prefer functions over classes: + And if you don't have state or refs, prefer normal functions (not arrow functions) over classes: ```javascript @@ -63,6 +63,11 @@ } } + // bad (since arrow functions do not have a "name" property) + const Listing = ({ hello }) => ( +
{hello}
+ ); + // good function Listing({ hello }) { return
{hello}
; @@ -149,7 +154,7 @@ superLongParam="bar" anotherSuperLongParam="baz" > - +
``` From 696776de15e3292a1e0b8867b86233c89cd34fba Mon Sep 17 00:00:00 2001 From: Nick Hwang Date: Fri, 29 Jan 2016 10:48:18 -0500 Subject: [PATCH 39/54] Bump to 4.0.2 --- package.json | 2 +- packages/eslint-config-hubspot/CHANGELOG.md | 4 ++++ packages/eslint-config-hubspot/package.json | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 1124640b75..3cc9cf78fd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hubspot-style", - "version": "4.0.1", + "version": "4.0.2", "description": "HubSpot's version of a mostly reasonable approach to JavaScript", "scripts": { "difftool": "./bin/difftool", diff --git a/packages/eslint-config-hubspot/CHANGELOG.md b/packages/eslint-config-hubspot/CHANGELOG.md index cceed1efba..9543ffe50a 100644 --- a/packages/eslint-config-hubspot/CHANGELOG.md +++ b/packages/eslint-config-hubspot/CHANGELOG.md @@ -1,3 +1,7 @@ +4.0.1 / 2016-01-24 +================== + - [hubspot] Allow `==` for `null` (#17) + 4.0.1 / 2016-01-24 ================== - [hubspot] Ignore `arrow-body-style` diff --git a/packages/eslint-config-hubspot/package.json b/packages/eslint-config-hubspot/package.json index cfda82a127..2d0303daf1 100644 --- a/packages/eslint-config-hubspot/package.json +++ b/packages/eslint-config-hubspot/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-hubspot", - "version": "4.0.1", + "version": "4.0.2", "description": "HubSpot's ESLint config, following our styleguide", "main": "index.js", "scripts": { From 04f61b1fd85c94d76b0a2fa4ee78714f5173f1b3 Mon Sep 17 00:00:00 2001 From: Nick Hwang Date: Thu, 4 Feb 2016 11:47:06 -0500 Subject: [PATCH 40/54] Update with airbnb/javascript@5.0.0 Major changes: - disallow unneeded ternary expressions - Avoid lexical declarations in case/default clauses --- README.md | 87 ++++++++++++++++++- package.json | 2 +- packages/eslint-config-hubspot/CHANGELOG.md | 6 ++ packages/eslint-config-hubspot/package.json | 2 +- .../rules/best-practices.js | 3 + packages/eslint-config-hubspot/rules/style.js | 4 +- 6 files changed, 99 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index f891c93b71..55b01afdd0 100644 --- a/README.md +++ b/README.md @@ -704,7 +704,7 @@ Other Style Guides (from Airbnb) > 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. ```javascript // bad @@ -737,7 +737,7 @@ Other Style Guides (from Airbnb) }); // good - [1, 2, 3].map(number => { + [1, 2, 3].map((number) => { const nextNumber = number + 1; return `A string containing the ${nextNumber}.`; }); @@ -1266,6 +1266,89 @@ Other Style Guides (from Airbnb) ``` - [15.4](#15.4) For more information see [Truth Equality and JavaScript](http://javascriptweblog.wordpress.com/2011/02/07/truth-equality-and-javascript/#more-2108) by Angus Croll. + - [15.5](#15.5) Use braces to create blocks in `case` and `default` clauses that contain lexical declarations (e.g. `let`, `const`, `function`, and `class`). + + > Why? Lexical declarations are visible in the entire `switch` block but only get initialized when assigned, which only happens when its `case` is reached. This causes problems when multiple `case` clauses attempt to define the same thing. + + eslint rules: [`no-case-declarations`](http://eslint.org/docs/rules/no-case-declarations.html). + + ```javascript + // bad + switch (foo) { + case 1: + let x = 1; + break; + case 2: + const y = 2; + break; + case 3: + function f() {} + break; + default: + class C {} + } + + // good + switch (foo) { + case 1: { + let x = 1; + break; + } + case 2: { + const y = 2; + break; + } + case 3: { + function f() {} + break; + } + case 4: + bar(); + break; + default: { + class C {} + } + } + ``` + + - [15.5](#15.5) Ternaries should not be nested and generally be single line expressions. + + eslint rules: [`no-nested-ternary`](http://eslint.org/docs/rules/no-nested-ternary.html). + + ```javascript + // bad + const foo = maybe1 > maybe2 + ? "bar" + : value1 > value2 ? "baz" : null; + + // better + const maybeNull = value1 > value2 ? 'baz' : null; + + const foo = maybe1 > maybe2 + ? 'bar' + : maybeNull; + + // best + const maybeNull = value1 > value2 ? 'baz' : null; + + const foo = maybe1 > maybe2 ? 'bar' : maybeNull; + ``` + + - [15.6](#15.6) Avoid unneeded ternary statements. + + eslint rules: [`no-unneeded-ternary`](http://eslint.org/docs/rules/no-unneeded-ternary.html). + + ```javascript + // bad + const foo = a ? a : b; + const bar = c ? true : false; + const baz = c ? false : true; + + // good + const foo = a || b; + const bar = !!c; + const baz = !c; + ``` **[⬆ back to top](#table-of-contents)** diff --git a/package.json b/package.json index 3cc9cf78fd..1b0fc46772 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hubspot-style", - "version": "4.0.2", + "version": "5.0.0", "description": "HubSpot's version of a mostly reasonable approach to JavaScript", "scripts": { "difftool": "./bin/difftool", diff --git a/packages/eslint-config-hubspot/CHANGELOG.md b/packages/eslint-config-hubspot/CHANGELOG.md index 9543ffe50a..9cb1182f91 100644 --- a/packages/eslint-config-hubspot/CHANGELOG.md +++ b/packages/eslint-config-hubspot/CHANGELOG.md @@ -1,3 +1,9 @@ +5.0.0 / 2016-02-03 +================== + - [breaking] disallow unneeded ternary expressions + - [breaking] Avoid lexical declarations in case/default clauses + - [dev deps] update `babel-tape-runner`, `eslint-plugin-react`, `react`, `tape` + 4.0.1 / 2016-01-24 ================== - [hubspot] Allow `==` for `null` (#17) diff --git a/packages/eslint-config-hubspot/package.json b/packages/eslint-config-hubspot/package.json index 2d0303daf1..cc3449384c 100644 --- a/packages/eslint-config-hubspot/package.json +++ b/packages/eslint-config-hubspot/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-hubspot", - "version": "4.0.2", + "version": "5.0.0", "description": "HubSpot's ESLint config, following our styleguide", "main": "index.js", "scripts": { diff --git a/packages/eslint-config-hubspot/rules/best-practices.js b/packages/eslint-config-hubspot/rules/best-practices.js index 4da3824d55..a2f22b363f 100644 --- a/packages/eslint-config-hubspot/rules/best-practices.js +++ b/packages/eslint-config-hubspot/rules/best-practices.js @@ -24,6 +24,9 @@ module.exports = { 'no-alert': 1, // disallow use of arguments.caller or arguments.callee 'no-caller': 2, + // disallow lexical declarations in case/default clauses + // http://eslint.org/docs/rules/no-case-declarations.html + 'no-case-declarations': 2, // disallow division operators explicitly at beginning of regular expression 'no-div-regex': 0, // disallow else after a return in an if diff --git a/packages/eslint-config-hubspot/rules/style.js b/packages/eslint-config-hubspot/rules/style.js index 8b8a1a272d..612d933a6c 100644 --- a/packages/eslint-config-hubspot/rules/style.js +++ b/packages/eslint-config-hubspot/rules/style.js @@ -74,7 +74,9 @@ module.exports = { // disallow dangling underscores in identifiers 'no-underscore-dangle': 0, // disallow the use of Boolean literals in conditional expressions - 'no-unneeded-ternary': 0, + // also, prefer `a || b` over `a ? a : b` + // http://eslint.org/docs/rules/no-unneeded-ternary + 'no-unneeded-ternary': [2, { 'defaultAssignment': false }], // require padding inside curly braces 'object-curly-spacing': [0, 'always'], // allow just one var statement per function From bcc553d837d08035cc2a8829e028a99fbe69138f Mon Sep 17 00:00:00 2001 From: Nick Hwang Date: Mon, 8 Feb 2016 16:48:09 -0500 Subject: [PATCH 41/54] Update deps and fix test --- packages/eslint-config-hubspot/package.json | 12 +++++++----- .../eslint-config-hubspot/rules/best-practices.js | 2 +- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/packages/eslint-config-hubspot/package.json b/packages/eslint-config-hubspot/package.json index cc3449384c..da43c56f17 100644 --- a/packages/eslint-config-hubspot/package.json +++ b/packages/eslint-config-hubspot/package.json @@ -31,13 +31,15 @@ "url": "https://github.com/HubSpot/javascript/issues" }, "homepage": "https://github.com/HubSpot/javascript", + "dependencies": { + "eslint": "^1.10.3", + "eslint-plugin-react": "^3.16.1" + }, "devDependencies": { - "babel-plugin-transform-export-extensions": "^6.4.0", - "babel-plugin-transform-strict-mode": "^6.3.13", - "babel-preset-es2015": "^6.3.13", + "babel-plugin-transform-export-extensions": "^6.5.0", + "babel-plugin-transform-strict-mode": "^6.5.0", + "babel-preset-es2015": "^6.5.0", "babel-tape-runner": "2.0.0", - "eslint": "^1.10.3", - "eslint-plugin-react": "^3.16.1", "faucet": "0.0.1", "parallelshell": "^2.0.0", "react": "^0.14.7", diff --git a/packages/eslint-config-hubspot/rules/best-practices.js b/packages/eslint-config-hubspot/rules/best-practices.js index a2f22b363f..9c7501248b 100644 --- a/packages/eslint-config-hubspot/rules/best-practices.js +++ b/packages/eslint-config-hubspot/rules/best-practices.js @@ -17,7 +17,7 @@ module.exports = { // enforces consistent newlines before or after dots 'dot-location': 0, // require the use of === and !==, except when comparing to null - 'eqeqeq': [2, "allow-null"], + 'eqeqeq': [2, 'allow-null'], // make sure for-in loops have an if statement 'guard-for-in': 2, // disallow the use of alert, confirm, and prompt From 719046875ac499213e564cde7a4ed285de9efb22 Mon Sep 17 00:00:00 2001 From: Nick Hwang Date: Mon, 8 Feb 2016 22:23:54 -0500 Subject: [PATCH 42/54] Add experimental config and tests --- packages/eslint-config-hubspot/README.md | 13 +++- .../eslint-config-hubspot/experimental.js | 9 +++ packages/eslint-config-hubspot/package.json | 2 + .../rules/experimental.js | 25 +++++++ packages/eslint-config-hubspot/rules/react.js | 8 +-- .../eslint-config-hubspot/test/test-base.js | 21 ++++-- .../test/test-experimental.js | 67 +++++++++++++++++++ .../test/test-react-order.js | 5 +- 8 files changed, 135 insertions(+), 15 deletions(-) create mode 100644 packages/eslint-config-hubspot/experimental.js create mode 100644 packages/eslint-config-hubspot/rules/experimental.js create mode 100644 packages/eslint-config-hubspot/test/test-experimental.js diff --git a/packages/eslint-config-hubspot/README.md b/packages/eslint-config-hubspot/README.md index dbd5c9559b..75fe010200 100644 --- a/packages/eslint-config-hubspot/README.md +++ b/packages/eslint-config-hubspot/README.md @@ -13,8 +13,9 @@ We export three ESLint configurations for your usage. ### eslint-config-hubspot -Our default export contains all of our ESLint rules, including EcmaScript 6+ -and React. It requires `eslint` and `eslint-plugin-react`. +Our default export contains all of our ESLint rules, including EcmaScript 6+ and +React, but excludes experimental features. It requires `eslint` and +`eslint-plugin-react`. 1. `npm install --save-dev eslint-config-hubspot eslint-plugin-react eslint` 2. add `"extends": "hubspot"` to your .eslintrc @@ -26,6 +27,14 @@ Lints ES6+ but does not lint React. Requires `eslint`. 1. `npm install --save-dev eslint-config-hubspot eslint` 2. add `"extends": "hubspot/base"` to your .eslintrc +### eslint-config-hubspot/experimental + +Lints EcmaScript 6+, React, and experimental features. It requires `eslint`, +`eslint-plugin-react`, `eslint-plugin-babel`, and `babel-eslint`. + +1. `npm install --save-dev eslint-config-hubspot eslint-plugin-react eslint-plugin-babel babel-eslint eslint` +2. add `"extends": "hubspot/experimental"` to your .eslintrc + ### eslint-config-hubspot/legacy Lints ES5 and below. Only requires `eslint`. diff --git a/packages/eslint-config-hubspot/experimental.js b/packages/eslint-config-hubspot/experimental.js new file mode 100644 index 0000000000..83e0d55da4 --- /dev/null +++ b/packages/eslint-config-hubspot/experimental.js @@ -0,0 +1,9 @@ +module.exports = { + extends: [ + 'eslint-config-hubspot/base', + 'eslint-config-hubspot/rules/strict', + 'eslint-config-hubspot/rules/react', + 'eslint-config-hubspot/rules/experimental' + ].map(require.resolve), + rules: {} +}; diff --git a/packages/eslint-config-hubspot/package.json b/packages/eslint-config-hubspot/package.json index da43c56f17..4953842b40 100644 --- a/packages/eslint-config-hubspot/package.json +++ b/packages/eslint-config-hubspot/package.json @@ -32,7 +32,9 @@ }, "homepage": "https://github.com/HubSpot/javascript", "dependencies": { + "babel-eslint": "^4.1.8", "eslint": "^1.10.3", + "eslint-plugin-babel": "^3.1.0", "eslint-plugin-react": "^3.16.1" }, "devDependencies": { diff --git a/packages/eslint-config-hubspot/rules/experimental.js b/packages/eslint-config-hubspot/rules/experimental.js new file mode 100644 index 0000000000..23fc040593 --- /dev/null +++ b/packages/eslint-config-hubspot/rules/experimental.js @@ -0,0 +1,25 @@ +module.exports = { + 'parser': 'babel-eslint', + 'plugins': [ + 'babel' + ], + 'ecmaFeatures': { + 'experimentalObjectRestSpread': true, + }, + 'rules': { + // handles async/await functions correctly + 'babel/generator-star-spacing': [2, {'before': false, 'after': true}], + // ignores capitalized decorators (@Decorator) + 'babel/new-cap': [2, { 'newIsCap': true, 'capIsNew': false }], + // handles destructuring arrays with flow type in function parameters + 'babel/array-bracket-spacing': [2, 'never'], + // doesn't complain about export x from "mod"; or export * as x from "mod"; + 'babel/object-curly-spacing': [0, 'always'], + // doesn't fail when using object spread (...obj) + 'babel/object-shorthand': [2, 'always'], + // handles async functions correctly + 'babel/arrow-parens': 0, + // guard against awaiting async functions inside of a loop + 'babel/no-await-in-loop': 2 + } +}; diff --git a/packages/eslint-config-hubspot/rules/react.js b/packages/eslint-config-hubspot/rules/react.js index f6c76b9837..b382715c63 100644 --- a/packages/eslint-config-hubspot/rules/react.js +++ b/packages/eslint-config-hubspot/rules/react.js @@ -106,7 +106,7 @@ module.exports = { 'react/prefer-es6-class': [0, '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: [] }], + '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, @@ -150,9 +150,9 @@ module.exports = { // 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 + 'declaration': true, + 'assignment': true, + 'return': true }] } }; diff --git a/packages/eslint-config-hubspot/test/test-base.js b/packages/eslint-config-hubspot/test/test-base.js index 24aa884cd0..4622ff2809 100644 --- a/packages/eslint-config-hubspot/test/test-base.js +++ b/packages/eslint-config-hubspot/test/test-base.js @@ -6,19 +6,21 @@ const files = { base: require('../base') }; -fs.readdirSync(path.join(__dirname, '../rules')).forEach(name => { - if (name === 'react.js') { - return; - } +fs.readdirSync(path.join(__dirname, '../rules')) + .filter(name => !/eslintrc/.test(name)) + .forEach(name => { + if (/^(react|experimental).js$/.test(name)) { + return; + } - files[name] = require(`../rules/${name}`); -}); + 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.plan(3); t.notOk(config.plugins, 'plugins is unspecified'); @@ -26,5 +28,10 @@ Object.keys(files).forEach(name => { const reactRuleIds = Object.keys(config.rules) .filter(ruleId => ruleId.indexOf('react/') === 0); t.deepEquals(reactRuleIds, [], 'there are no react/ rules'); + + // scan rules for babel/ and fail if any exist + const babelRuleIds = Object.keys(config.rules) + .filter(ruleId => ruleId.indexOf('babel/') === 0); + t.deepEquals(babelRuleIds, [], 'there are no babel/ rules'); }); }); diff --git a/packages/eslint-config-hubspot/test/test-experimental.js b/packages/eslint-config-hubspot/test/test-experimental.js new file mode 100644 index 0000000000..b06eab1a9b --- /dev/null +++ b/packages/eslint-config-hubspot/test/test-experimental.js @@ -0,0 +1,67 @@ +import test from 'tape'; +import { CLIEngine } from 'eslint'; +import experimentalRules from '../rules/experimental'; + +const cli = new CLIEngine({ + useEslintrc: false, + baseConfig: { + extends: 'hubspot/experimental' + }, + rules: { + 'indent': 0, + 'no-unused-vars': 0 + }, +}); + +function lint(text) { + return cli.executeOnText(text).results[0]; +} + +test('validate experimental features', t => { + t.test('make sure our eslintrc has Babel linting dependencies', t => { + t.plan(1); + t.equal(experimentalRules.plugins[0], 'babel', 'uses eslint-plugin-babel'); + }); + + t.test('babel/generator-star-spacing', t => { + t.plan(6); + + const good = lint('function* generator() {}\n'); + t.notOk(good.warningCount, 'no warnings'); + t.notOk(good.errorCount, 'no errors'); + t.deepEquals(good.messages, [], 'no messages in results'); + + const bad = lint('function *generator() {}\n'); + t.notOk(bad.warningCount, 'no warnings'); + t.ok(bad.errorCount, 'should have errors'); + t.notDeepEqual(bad.messages, [], 'should have messages in results'); + }); + + t.test('babel/new-cap', t => { + t.plan(3); + + const good = lint([ + 'function Decorator() {}', + '@Decorator', + 'class Component {}\n' + ].join('\n')); + t.notOk(good.warningCount, 'no warnings'); + t.notOk(good.errorCount, 'no errors'); + t.deepEquals(good.messages, [], 'no messages in results'); + }); + + t.test('babel/no-await-in-loop', t => { + t.plan(3); + + const bad = lint([ + 'async function foo() {', + ' for (const bar of {}) {', + ' await(bar);', + ' }', + '}\n' + ].join('\n')); + t.notOk(bad.warningCount, 'no warnings'); + t.ok(bad.errorCount, 'should have errors'); + t.notDeepEqual(bad.messages, [], 'should have messages in results'); + }); +}); diff --git a/packages/eslint-config-hubspot/test/test-react-order.js b/packages/eslint-config-hubspot/test/test-react-order.js index a44c05c582..b037b188df 100644 --- a/packages/eslint-config-hubspot/test/test-react-order.js +++ b/packages/eslint-config-hubspot/test/test-react-order.js @@ -1,11 +1,12 @@ import test from 'tape'; import { CLIEngine } from 'eslint'; -import eslintrc from '../'; import reactRules from '../rules/react'; const cli = new CLIEngine({ useEslintrc: false, - baseConfig: eslintrc, + baseConfig: { + extends: 'hubspot' + }, // This rule fails when executing on text. rules: {indent: 0}, From 5fd81ff0aa0794fce6e809e863782b9b7ec7b115 Mon Sep 17 00:00:00 2001 From: Nick Hwang Date: Tue, 9 Feb 2016 11:42:29 -0500 Subject: [PATCH 43/54] Bump version --- package.json | 2 +- packages/eslint-config-hubspot/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 1b0fc46772..cc3fbe5920 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hubspot-style", - "version": "5.0.0", + "version": "5.1.0", "description": "HubSpot's version of a mostly reasonable approach to JavaScript", "scripts": { "difftool": "./bin/difftool", diff --git a/packages/eslint-config-hubspot/package.json b/packages/eslint-config-hubspot/package.json index 4953842b40..ca9ee4fca8 100644 --- a/packages/eslint-config-hubspot/package.json +++ b/packages/eslint-config-hubspot/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-hubspot", - "version": "5.0.0", + "version": "5.1.0", "description": "HubSpot's ESLint config, following our styleguide", "main": "index.js", "scripts": { From 57516057485d655bb180ebc8092505310b104fc0 Mon Sep 17 00:00:00 2001 From: Nick Hwang Date: Thu, 11 Feb 2016 13:39:02 -0500 Subject: [PATCH 44/54] Remove no-param-reassign error Makes using some functions of `Immutable` and `GeneralStore` a pain. Specifically, using `Immutable#withMutations` and the factory patter for `GeneralStore` --- package.json | 2 +- packages/eslint-config-hubspot/CHANGELOG.md | 8 ++++++++ packages/eslint-config-hubspot/package.json | 2 +- packages/eslint-config-hubspot/rules/best-practices.js | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index cc3fbe5920..9571f9854d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hubspot-style", - "version": "5.1.0", + "version": "5.2.0", "description": "HubSpot's version of a mostly reasonable approach to JavaScript", "scripts": { "difftool": "./bin/difftool", diff --git a/packages/eslint-config-hubspot/CHANGELOG.md b/packages/eslint-config-hubspot/CHANGELOG.md index 9cb1182f91..fad41a693c 100644 --- a/packages/eslint-config-hubspot/CHANGELOG.md +++ b/packages/eslint-config-hubspot/CHANGELOG.md @@ -1,3 +1,11 @@ +5.2.0 / 2016-02-11 +================== +- [hubspot] Remove error for 'no-param-reassign' for Immutable and GeneralStore + +5.1.0 / 2016-02-09 +================== +- [hubspot] Add `hubspot/experimental` config for ES7 features + 5.0.0 / 2016-02-03 ================== - [breaking] disallow unneeded ternary expressions diff --git a/packages/eslint-config-hubspot/package.json b/packages/eslint-config-hubspot/package.json index ca9ee4fca8..f0d4404afe 100644 --- a/packages/eslint-config-hubspot/package.json +++ b/packages/eslint-config-hubspot/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-hubspot", - "version": "5.1.0", + "version": "5.2.0", "description": "HubSpot's ESLint config, following our styleguide", "main": "index.js", "scripts": { diff --git a/packages/eslint-config-hubspot/rules/best-practices.js b/packages/eslint-config-hubspot/rules/best-practices.js index 9c7501248b..7edf5a5959 100644 --- a/packages/eslint-config-hubspot/rules/best-practices.js +++ b/packages/eslint-config-hubspot/rules/best-practices.js @@ -79,7 +79,7 @@ module.exports = { // disallow reassignment of function parameters // disallow parameter object manipulation // rule: http://eslint.org/docs/rules/no-param-reassign.html - 'no-param-reassign': [2, { 'props': false }], + 'no-param-reassign': [0, { 'props': true }], // disallow use of process.env 'no-process-env': 0, // disallow usage of __proto__ property From 1a165b340605b3ac1f6f07d56fccbf27f1459b90 Mon Sep 17 00:00:00 2001 From: Nick Hwang Date: Sun, 21 Feb 2016 18:21:37 -0500 Subject: [PATCH 45/54] Update with airbnb/javascript@6.0.1 Bumps HubSpot/javascript to 6.0.0 --- README.md | 115 +++++++++++++++++- package.json | 2 +- packages/eslint-config-hubspot/CHANGELOG.md | 19 +++ packages/eslint-config-hubspot/package.json | 16 ++- .../rules/best-practices.js | 21 +++- .../eslint-config-hubspot/rules/errors.js | 2 - packages/eslint-config-hubspot/rules/es6.js | 58 +++++---- .../rules/experimental.js | 13 +- .../eslint-config-hubspot/rules/legacy.js | 2 + packages/eslint-config-hubspot/rules/react.js | 9 +- packages/eslint-config-hubspot/rules/style.js | 26 +++- .../eslint-config-hubspot/rules/variables.js | 6 + 12 files changed, 235 insertions(+), 54 deletions(-) diff --git a/README.md b/README.md index 55b01afdd0..07f79506f4 100644 --- a/README.md +++ b/README.md @@ -302,7 +302,7 @@ Other Style Guides (from Airbnb) }; ``` - - [3.9](#3.9) Don't wrap object literals in extra parentheses + - [3.9](#3.9) Don't wrap object literals in extra parentheses except for arrow function returns ```javascript // bad @@ -312,10 +312,16 @@ Other Style Guides (from Airbnb) }); // good - const bad = { + const good = { hello: 'world', foo: 'bar' }; + + // okay + const okay = () => ({ + hello: 'world', + foo: 'bar' + }); ``` **[⬆ back to top](#table-of-contents)** @@ -367,6 +373,54 @@ Other Style Guides (from Airbnb) 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 @@ -468,7 +522,7 @@ Other Style Guides (from Airbnb) ``` - - [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. @@ -483,6 +537,11 @@ Other Style Guides (from Airbnb) return ['How are you, ', name, '?'].join(); } + // bad + function sayHi(name) { + return `How are you, ${ name }?`; + } + // good function sayHi(name) { return `How are you, ${name}?`; @@ -556,7 +615,7 @@ Other Style Guides (from Airbnb) ``` - - [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`. @@ -792,6 +851,19 @@ Other Style Guides (from Airbnb) }); ``` + - [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)** @@ -904,6 +976,34 @@ Other Style Guides (from Airbnb) } ``` + - [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)** @@ -1613,8 +1713,8 @@ Other Style Guides (from Airbnb) })(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 @@ -1651,6 +1751,9 @@ Other Style Guides (from Airbnb) .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/package.json b/package.json index 9571f9854d..f4aae760df 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hubspot-style", - "version": "5.2.0", + "version": "6.0.0", "description": "HubSpot's version of a mostly reasonable approach to JavaScript", "scripts": { "difftool": "./bin/difftool", diff --git a/packages/eslint-config-hubspot/CHANGELOG.md b/packages/eslint-config-hubspot/CHANGELOG.md index fad41a693c..2885af879b 100644 --- a/packages/eslint-config-hubspot/CHANGELOG.md +++ b/packages/eslint-config-hubspot/CHANGELOG.md @@ -1,3 +1,22 @@ +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` (#730) (#730) (#730) (#730) +- [fix] disable `newline-per-chained-call` due to an `eslint` bug (#748) + 5.2.0 / 2016-02-11 ================== - [hubspot] Remove error for 'no-param-reassign' for Immutable and GeneralStore diff --git a/packages/eslint-config-hubspot/package.json b/packages/eslint-config-hubspot/package.json index f0d4404afe..6eee70221b 100644 --- a/packages/eslint-config-hubspot/package.json +++ b/packages/eslint-config-hubspot/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-hubspot", - "version": "5.2.0", + "version": "6.0.0", "description": "HubSpot's ESLint config, following our styleguide", "main": "index.js", "scripts": { @@ -31,24 +31,22 @@ "url": "https://github.com/HubSpot/javascript/issues" }, "homepage": "https://github.com/HubSpot/javascript", - "dependencies": { - "babel-eslint": "^4.1.8", - "eslint": "^1.10.3", - "eslint-plugin-babel": "^3.1.0", - "eslint-plugin-react": "^3.16.1" - }, "devDependencies": { + "babel-eslint": "^5.0.0", "babel-plugin-transform-export-extensions": "^6.5.0", "babel-plugin-transform-strict-mode": "^6.5.0", "babel-preset-es2015": "^6.5.0", "babel-tape-runner": "2.0.0", + "eslint": "^2.2.0", + "eslint-plugin-babel": "^3.1.0", + "eslint-plugin-react": "^4.0.0", "faucet": "0.0.1", "parallelshell": "^2.0.0", "react": "^0.14.7", "tape": "^4.4.0" }, "peerDependencies": { - "eslint": "^1.0.0", - "eslint-plugin-react": "^3.0.0" + "eslint": "^2.2.0", + "eslint-plugin-react": "^4.0.0" } } diff --git a/packages/eslint-config-hubspot/rules/best-practices.js b/packages/eslint-config-hubspot/rules/best-practices.js index 7edf5a5959..c95ee54d2a 100644 --- a/packages/eslint-config-hubspot/rules/best-practices.js +++ b/packages/eslint-config-hubspot/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, 'allow-null'], // 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-hubspot/rules/errors.js b/packages/eslint-config-hubspot/rules/errors.js index 58cdc41d41..1c1addf5fa 100644 --- a/packages/eslint-config-hubspot/rules/errors.js +++ b/packages/eslint-config-hubspot/rules/errors.js @@ -1,7 +1,5 @@ module.exports = { 'rules': { - // disallow trailing commas in object literals - 'comma-dangle': 0, // disallow assignment in conditional expressions 'no-cond-assign': [2, 'always'], // disallow use of console diff --git a/packages/eslint-config-hubspot/rules/es6.js b/packages/eslint-config-hubspot/rules/es6.js index b8eb830e20..be82a4f6fc 100644 --- a/packages/eslint-config-hubspot/rules/es6.js +++ b/packages/eslint-config-hubspot/rules/es6.js @@ -1,26 +1,16 @@ 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, - 'experimentalObjectRestSpread': true + 'parserOptions': { + 'ecmaVersion': 6, + 'sourceType': 'module', + 'ecmaFeatures': { + 'jsx': true, + 'generators': false, + 'objectLiteralDuplicateProperties': false, + 'experimentalObjectRestSpread': true + } }, 'rules': { // enforces no braces where they can be omitted @@ -31,18 +21,32 @@ module.exports = { // 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 }], + // require trailing commas in multiline object literals + 'comma-dangle': [0, 'always-multiline'], // 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 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'], @@ -54,10 +58,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': [0, 'never'], + // 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-hubspot/rules/experimental.js b/packages/eslint-config-hubspot/rules/experimental.js index 23fc040593..152e4e4939 100644 --- a/packages/eslint-config-hubspot/rules/experimental.js +++ b/packages/eslint-config-hubspot/rules/experimental.js @@ -3,8 +3,17 @@ module.exports = { 'plugins': [ 'babel' ], - 'ecmaFeatures': { - 'experimentalObjectRestSpread': true, + 'env': { + 'es6': true + }, + 'parserOptions': { + 'ecmaVersion': 6, + 'sourceType': 'module', + 'ecmaFeatures': { + 'generators': true, + 'objectLiteralDuplicateProperties': false, + 'experimentalObjectRestSpread': true + } }, 'rules': { // handles async/await functions correctly diff --git a/packages/eslint-config-hubspot/rules/legacy.js b/packages/eslint-config-hubspot/rules/legacy.js index e94c774f26..dc34856f5e 100644 --- a/packages/eslint-config-hubspot/rules/legacy.js +++ b/packages/eslint-config-hubspot/rules/legacy.js @@ -1,5 +1,7 @@ module.exports = { 'rules': { + // disallow trailing commas in object literals + 'comma-dangle': [2, 'never'], // 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. diff --git a/packages/eslint-config-hubspot/rules/react.js b/packages/eslint-config-hubspot/rules/react.js index b382715c63..16f7ccb3eb 100644 --- a/packages/eslint-config-hubspot/rules/react.js +++ b/packages/eslint-config-hubspot/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,6 +116,9 @@ 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, { diff --git a/packages/eslint-config-hubspot/rules/style.js b/packages/eslint-config-hubspot/rules/style.js index 612d933a6c..ce8f78820f 100644 --- a/packages/eslint-config-hubspot/rules/style.js +++ b/packages/eslint-config-hubspot/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': [0, { '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': [0, '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-hubspot/rules/variables.js b/packages/eslint-config-hubspot/rules/variables.js index 59914313f9..3bfcc83fde 100644 --- a/packages/eslint-config-hubspot/rules/variables.js +++ b/packages/eslint-config-hubspot/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 From 90b3feb18030e7e2a763d2be2eacf064f5f02664 Mon Sep 17 00:00:00 2001 From: George Banis Date: Tue, 1 Mar 2016 11:48:30 -0500 Subject: [PATCH 46/54] Use .js extension instead of .jsx --- react/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/react/README.md b/react/README.md index e371d21867..dbe8d1913e 100644 --- a/react/README.md +++ b/react/README.md @@ -76,8 +76,8 @@ ## Naming - - **Extensions**: Use `.jsx` extension for React components. - - **Filename**: Use PascalCase for filenames. E.g., `ReservationCard.jsx`. + - **Extensions**: Use `.js` extension for React components. + - **Filename**: Use PascalCase for filenames. E.g., `ReservationCard.js`. - **Reference Naming**: Use PascalCase for React components and camelCase for their instances. eslint: [`react/jsx-pascal-case`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-pascal-case.md) ```javascript @@ -94,7 +94,7 @@ 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.js` should have a reference name of `ReservationCard`. However, for root components of a directory, use `index.js` as the filename and use the directory name as the component name: ```javascript // bad From 933d7b37e8e8163f1c830c4b73f056c7e1efd5d2 Mon Sep 17 00:00:00 2001 From: Nick Hwang Date: Wed, 2 Mar 2016 21:35:51 -0500 Subject: [PATCH 47/54] Update with airbnb/javascript@6.0.2 Bumps HubSpot/javascript to 6.0.1 --- README.md | 18 +++++++++--------- package.json | 2 +- packages/eslint-config-hubspot/CHANGELOG.md | 4 ++++ packages/eslint-config-hubspot/package.json | 2 +- packages/eslint-config-hubspot/rules/es6.js | 2 +- 5 files changed, 16 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 07f79506f4..8dab1d4e3a 100644 --- a/README.md +++ b/README.md @@ -786,15 +786,15 @@ Other Style Guides (from Airbnb) > Why not? If you plan on returning an object. ```javascript - // good - [1, 2, 3].map(number => `A string containing the ${number}.`); - // bad [1, 2, 3].map(number => { const nextNumber = number + 1; `A string containing the ${nextNumber}.`; }); + // good + [1, 2, 3].map(number => `A string containing the ${number}.`); + // good [1, 2, 3].map((number) => { const nextNumber = number + 1; @@ -1060,7 +1060,7 @@ Other Style Guides (from Airbnb) - [11.1](#11.1) Don't use iterators. Prefer JavaScript's higher-order functions like `map()` and `reduce()` instead of loops like `for-of`. eslint: [`no-iterator`](http://eslint.org/docs/rules/no-iterator.html) - > 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. ```javascript const numbers = [1, 2, 3, 4, 5]; @@ -1411,7 +1411,7 @@ Other Style Guides (from Airbnb) } ``` - - [15.5](#15.5) Ternaries should not be nested and generally be single line expressions. + - [15.6](#15.6) Ternaries should not be nested and generally be single line expressions. eslint rules: [`no-nested-ternary`](http://eslint.org/docs/rules/no-nested-ternary.html). @@ -1434,7 +1434,7 @@ Other Style Guides (from Airbnb) const foo = maybe1 > maybe2 ? 'bar' : maybeNull; ``` - - [15.6](#15.6) Avoid unneeded ternary statements. + - [15.7](#15.7) Avoid unneeded ternary statements. eslint rules: [`no-unneeded-ternary`](http://eslint.org/docs/rules/no-unneeded-ternary.html). @@ -1577,7 +1577,7 @@ Other Style Guides (from Airbnb) } ``` - - [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`. + - [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`. - [17.4](#17.4) Use `// FIXME:` to annotate problems. @@ -1737,7 +1737,7 @@ Other Style Guides (from Airbnb) .updateCount(); // bad - const leds = stage.selectAll('.led').data(data).enter().append('svg:svg').class('led', true) + const leds = stage.selectAll('.led').data(data).enter().append('svg:svg').classed('led', true) .attr('width', (radius + margin) * 2).append('svg:g') .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')') .call(tron.led); @@ -2244,7 +2244,7 @@ Other Style Guides (from Airbnb) ## Accessors - [23.1](#23.1) Accessor functions for properties are not required. - - [23.2](#23.2) If you do make accessor functions use getVal() and setVal('hello'). + - [23.2](#23.2) Do not use JavaScript getters/setters as they cause unexpected side effects and are harder to test, maintain, and reason about. Instead, if you do make accessor functions, use getVal() and setVal('hello'). ```javascript // bad diff --git a/package.json b/package.json index f4aae760df..346a6be959 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hubspot-style", - "version": "6.0.0", + "version": "6.0.1", "description": "HubSpot's version of a mostly reasonable approach to JavaScript", "scripts": { "difftool": "./bin/difftool", diff --git a/packages/eslint-config-hubspot/CHANGELOG.md b/packages/eslint-config-hubspot/CHANGELOG.md index 2885af879b..48221a694d 100644 --- a/packages/eslint-config-hubspot/CHANGELOG.md +++ b/packages/eslint-config-hubspot/CHANGELOG.md @@ -1,3 +1,7 @@ +6.0.1 / 2016-02-22 +================== +- [fix] disable [`no-confusing-arrow`][no-confusing-arrow] due to an `eslint` bug ([#752](https://github.com/airbnb/javascript/issues/752)) + 6.0.0 / 2016-02-21 ================== - [breaking] enable `array-callback-return` diff --git a/packages/eslint-config-hubspot/package.json b/packages/eslint-config-hubspot/package.json index 6eee70221b..0a96850cb0 100644 --- a/packages/eslint-config-hubspot/package.json +++ b/packages/eslint-config-hubspot/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-hubspot", - "version": "6.0.0", + "version": "6.0.1", "description": "HubSpot's ESLint config, following our styleguide", "main": "index.js", "scripts": { diff --git a/packages/eslint-config-hubspot/rules/es6.js b/packages/eslint-config-hubspot/rules/es6.js index be82a4f6fc..e1fcb9662c 100644 --- a/packages/eslint-config-hubspot/rules/es6.js +++ b/packages/eslint-config-hubspot/rules/es6.js @@ -31,7 +31,7 @@ module.exports = { '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, + 'no-confusing-arrow': 0, // disallow modifying variables that are declared using const 'no-const-assign': 2, // disallow symbol constructor From 6c6dba381dacda6e9f95cdcee4e51f2b14daf2ce Mon Sep 17 00:00:00 2001 From: Nick Hwang Date: Tue, 8 Mar 2016 11:04:09 -0500 Subject: [PATCH 48/54] Update with airbnb/javascript@6.1.0 Bumps HubSpot/javascript to 6.1.0 --- README.md | 6 ++++-- package.json | 2 +- packages/eslint-config-hubspot/CHANGELOG.md | 7 +++++++ packages/eslint-config-hubspot/README.md | 2 +- packages/eslint-config-hubspot/package.json | 8 ++++---- packages/eslint-config-hubspot/rules/es6.js | 2 ++ packages/eslint-config-hubspot/rules/react.js | 13 ++++++++++--- packages/eslint-config-hubspot/rules/style.js | 4 +++- 8 files changed, 32 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 8dab1d4e3a..72e1eb2d28 100644 --- a/README.md +++ b/README.md @@ -463,7 +463,7 @@ Other Style Guides (from Airbnb) const [first, second] = arr; ``` - - [5.3](#5.3) Use object destructuring for multiple return values, not array destructuring. + - [5.3](#5.3) Use object destructuring for multiple return values, not array destructuring. jscs: [`disallowArrayDestructuringReturn`](http://jscs.info/rule/disallowArrayDestructuringReturn) > Why? You can add new properties over time or change the order of things without breaking call sites. @@ -2624,6 +2624,7 @@ Other Style Guides (from Airbnb) - **Billabong**: [billabong/javascript](https://github.com/billabong/javascript) - **Bisk**: [bisk/javascript](https://github.com/Bisk/javascript/) - **Blendle**: [blendle/javascript](https://github.com/blendle/javascript) + - **Brainshark**: [brainshark/javascript](https://github.com/brainshark/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) @@ -2663,7 +2664,7 @@ Other Style Guides (from Airbnb) - **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) + - **REI**: [reidev/js-style-guide](https://github.com/rei/code-style-guides/blob/master/docs/javascript.md) - **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) @@ -2698,6 +2699,7 @@ Other Style Guides (from Airbnb) - ![ru](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Russia.png) **Russian**: [uprock/javascript](https://github.com/uprock/javascript) - ![es](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Spain.png) **Spanish**: [paolocarrasco/javascript-style-guide](https://github.com/paolocarrasco/javascript-style-guide) - ![th](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Thailand.png) **Thai**: [lvarayut/javascript-style-guide](https://github.com/lvarayut/javascript-style-guide) + - ![vn](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Vietnam.png) **Vietnam**: [giangpii/javascript-style-guide](https://github.com/giangpii/javascript-style-guide) ## The JavaScript Style Guide Guide diff --git a/package.json b/package.json index 346a6be959..f16c153d5a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hubspot-style", - "version": "6.0.1", + "version": "6.1.0", "description": "HubSpot's version of a mostly reasonable approach to JavaScript", "scripts": { "difftool": "./bin/difftool", diff --git a/packages/eslint-config-hubspot/CHANGELOG.md b/packages/eslint-config-hubspot/CHANGELOG.md index 48221a694d..839fcbea09 100644 --- a/packages/eslint-config-hubspot/CHANGELOG.md +++ b/packages/eslint-config-hubspot/CHANGELOG.md @@ -1,3 +1,10 @@ +6.1.0 / 2016-02-22 +================== +- [new] enable [`react/prefer-stateless-function`][react/prefer-stateless-function] +- [dev deps] update `react-plugin-eslint`, `eslint`, `tape` +- [hubspot] enable warning for deprecated - v0.14 +- [hubspot] enable `no-is-mounted` to prepare for deprecation + 6.0.1 / 2016-02-22 ================== - [fix] disable [`no-confusing-arrow`][no-confusing-arrow] due to an `eslint` bug ([#752](https://github.com/airbnb/javascript/issues/752)) diff --git a/packages/eslint-config-hubspot/README.md b/packages/eslint-config-hubspot/README.md index 75fe010200..8b51d02bed 100644 --- a/packages/eslint-config-hubspot/README.md +++ b/packages/eslint-config-hubspot/README.md @@ -29,7 +29,7 @@ Lints ES6+ but does not lint React. Requires `eslint`. ### eslint-config-hubspot/experimental -Lints EcmaScript 6+, React, and experimental features. It requires `eslint`, +Lints EcmaScript 6+, React, and ES6/7 experimental features. It requires `eslint`, `eslint-plugin-react`, `eslint-plugin-babel`, and `babel-eslint`. 1. `npm install --save-dev eslint-config-hubspot eslint-plugin-react eslint-plugin-babel babel-eslint eslint` diff --git a/packages/eslint-config-hubspot/package.json b/packages/eslint-config-hubspot/package.json index 0a96850cb0..877e422c71 100644 --- a/packages/eslint-config-hubspot/package.json +++ b/packages/eslint-config-hubspot/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-hubspot", - "version": "6.0.1", + "version": "6.1.0", "description": "HubSpot's ESLint config, following our styleguide", "main": "index.js", "scripts": { @@ -37,13 +37,13 @@ "babel-plugin-transform-strict-mode": "^6.5.0", "babel-preset-es2015": "^6.5.0", "babel-tape-runner": "2.0.0", - "eslint": "^2.2.0", + "eslint": "^2.3.0", "eslint-plugin-babel": "^3.1.0", - "eslint-plugin-react": "^4.0.0", + "eslint-plugin-react": "^4.2.0", "faucet": "0.0.1", "parallelshell": "^2.0.0", "react": "^0.14.7", - "tape": "^4.4.0" + "tape": "^4.5.1" }, "peerDependencies": { "eslint": "^2.2.0", diff --git a/packages/eslint-config-hubspot/rules/es6.js b/packages/eslint-config-hubspot/rules/es6.js index e1fcb9662c..4783db126f 100644 --- a/packages/eslint-config-hubspot/rules/es6.js +++ b/packages/eslint-config-hubspot/rules/es6.js @@ -37,6 +37,8 @@ module.exports = { // disallow symbol constructor // http://eslint.org/docs/rules/no-new-symbol 'no-new-symbol': 2, + // disallow specific globals + 'no-restricted-globals': 0, // disallow specific imports // http://eslint.org/docs/rules/no-restricted-imports 'no-restricted-imports': 0, diff --git a/packages/eslint-config-hubspot/rules/react.js b/packages/eslint-config-hubspot/rules/react.js index 16f7ccb3eb..a12f9003ae 100644 --- a/packages/eslint-config-hubspot/rules/react.js +++ b/packages/eslint-config-hubspot/rules/react.js @@ -40,7 +40,11 @@ module.exports = { '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, + 'react/jsx-no-bind': [2, { + 'ignoreRefs': false, + 'allowArrowFunctions': false, + 'allowBind': false, + }], // 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 }], @@ -76,7 +80,7 @@ module.exports = { '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': [0, { 'react': '0.14.0' }], + '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'], @@ -88,7 +92,7 @@ module.exports = { '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': 0, + '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 }], @@ -104,6 +108,9 @@ module.exports = { // 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': [0, 'always'], + // Require stateless functions when not using lifecycle methods, setState or ref + // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/prefer-stateless-function.md + 'react/prefer-stateless-function': 2, // 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': [] }], diff --git a/packages/eslint-config-hubspot/rules/style.js b/packages/eslint-config-hubspot/rules/style.js index ce8f78820f..cce3ac374b 100644 --- a/packages/eslint-config-hubspot/rules/style.js +++ b/packages/eslint-config-hubspot/rules/style.js @@ -59,12 +59,14 @@ module.exports = { 'new-parens': 0, // allow/disallow an empty newline after var statement 'newline-after-var': 0, + // http://eslint.org/docs/rules/newline-before-return + 'newline-before-return': 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': [0, { 'ignoreChainWithDepth': 3 }], // disallow use of the Array constructor - 'no-array-constructor': 0, + 'no-array-constructor': 2, // disallow use of the continue statement 'no-continue': 0, // disallow comments inline after code From c3b2719e822083bb0a03f42e0fc6c4f0b751a985 Mon Sep 17 00:00:00 2001 From: Nick Hwang Date: Tue, 8 Mar 2016 11:22:57 -0500 Subject: [PATCH 49/54] Update and lock dependencies to fix experimental --- packages/eslint-config-hubspot/CHANGELOG.md | 1 + packages/eslint-config-hubspot/package.json | 12 ++++++------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/eslint-config-hubspot/CHANGELOG.md b/packages/eslint-config-hubspot/CHANGELOG.md index 839fcbea09..ab0ec2d194 100644 --- a/packages/eslint-config-hubspot/CHANGELOG.md +++ b/packages/eslint-config-hubspot/CHANGELOG.md @@ -4,6 +4,7 @@ - [dev deps] update `react-plugin-eslint`, `eslint`, `tape` - [hubspot] enable warning for deprecated - v0.14 - [hubspot] enable `no-is-mounted` to prepare for deprecation +- [hubspot] update and lock deps for experimental features 6.0.1 / 2016-02-22 ================== diff --git a/packages/eslint-config-hubspot/package.json b/packages/eslint-config-hubspot/package.json index 877e422c71..eea409bae6 100644 --- a/packages/eslint-config-hubspot/package.json +++ b/packages/eslint-config-hubspot/package.json @@ -32,15 +32,15 @@ }, "homepage": "https://github.com/HubSpot/javascript", "devDependencies": { - "babel-eslint": "^5.0.0", + "babel-eslint": "^6.0.0-beta.5", "babel-plugin-transform-export-extensions": "^6.5.0", - "babel-plugin-transform-strict-mode": "^6.5.0", - "babel-preset-es2015": "^6.5.0", - "babel-tape-runner": "2.0.0", - "eslint": "^2.3.0", + "babel-plugin-transform-strict-mode": "^6.6.5", + "babel-preset-es2015": "^6.6.0", + "babel-tape-runner": "^2.0.1", + "eslint": "2.2.0", "eslint-plugin-babel": "^3.1.0", "eslint-plugin-react": "^4.2.0", - "faucet": "0.0.1", + "faucet": "^0.0.1", "parallelshell": "^2.0.0", "react": "^0.14.7", "tape": "^4.5.1" From 022c6b40e5e806bb674910468a312d2d74695787 Mon Sep 17 00:00:00 2001 From: Nick Hwang Date: Fri, 18 Mar 2016 22:02:10 -0400 Subject: [PATCH 50/54] Update docs --- README.md | 402 +++++++++++++++++++++++++++++++----------------- react/README.md | 2 +- 2 files changed, 263 insertions(+), 141 deletions(-) diff --git a/README.md b/README.md index 72e1eb2d28..5a5b143012 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,8 @@ Other Style Guides (from Airbnb) ## Types - - [1.1](#1.1) **Primitives**: When you access a primitive type you work directly on its value. + + - [1.1](#types--primitives) **Primitives**: When you access a primitive type you work directly on its value. + `string` + `number` @@ -73,7 +74,9 @@ Other Style Guides (from Airbnb) console.log(foo, bar); // => 1, 9 ``` - - [1.2](#1.2) **Complex**: When you access a complex type you work on a reference to its value. + + + - [1.2](#types--complex) **Complex**: When you access a complex type you work on a reference to its value. + `object` + `array` @@ -92,7 +95,8 @@ Other Style Guides (from Airbnb) ## References - - [2.1](#2.1) Use `const` for all of your references; avoid using `var`. eslint: [`prefer-const`](http://eslint.org/docs/rules/prefer-const.html), [`no-const-assign`](http://eslint.org/docs/rules/no-const-assign.html) + + - [2.1](#references--prefer-const) Use `const` for all of your references; avoid using `var`. eslint: [`prefer-const`](http://eslint.org/docs/rules/prefer-const.html), [`no-const-assign`](http://eslint.org/docs/rules/no-const-assign.html) > Why? This ensures that you can't reassign your references, which can lead to bugs and difficult to comprehend code. @@ -106,7 +110,8 @@ Other Style Guides (from Airbnb) const b = 2; ``` - - [2.2](#2.2) If you must reassign references, use `let` instead of `var`. eslint: [`no-var`](http://eslint.org/docs/rules/no-var.html) jscs: [`disallowVar`](http://jscs.info/rule/disallowVar) + + - [2.2](#references--disallow-var) If you must reassign references, use `let` instead of `var`. eslint: [`no-var`](http://eslint.org/docs/rules/no-var.html) jscs: [`disallowVar`](http://jscs.info/rule/disallowVar) > Why? `let` is block-scoped rather than function-scoped like `var`. @@ -124,7 +129,8 @@ Other Style Guides (from Airbnb) } ``` - - [2.3](#2.3) Note that both `let` and `const` are block-scoped. + + - [2.3](#references--block-scope) Note that both `let` and `const` are block-scoped. ```javascript // const and let only exist in the blocks they are defined in. @@ -140,7 +146,8 @@ Other Style Guides (from Airbnb) ## Objects - - [3.1](#3.1) Use the literal syntax for object creation. eslint: [`no-new-object`](http://eslint.org/docs/rules/no-new-object.html) + + - [3.1](#objects--no-new) Use the literal syntax for object creation. eslint: [`no-new-object`](http://eslint.org/docs/rules/no-new-object.html) ```javascript // bad @@ -150,7 +157,8 @@ Other Style Guides (from Airbnb) const item = {}; ``` - - [3.2](#3.2) If your code will be executed in browsers in script context, don't use [reserved words](http://es5.github.io/#x7.6.1) as keys. It won't work in IE8. [More info](https://github.com/airbnb/javascript/issues/61). It’s OK to use them in ES6 modules and server-side code. jscs: [`disallowIdentiferNames`](http://jscs.info/rule/disallowIdentifierNames) + + - [3.2](#objects--reserved-words) If your code will be executed in browsers in script context, don't use [reserved words](http://es5.github.io/#x7.6.1) as keys. It won't work in IE8. [More info](https://github.com/airbnb/javascript/issues/61). It’s OK to use them in ES6 modules and server-side code. jscs: [`disallowIdentifierNames`](http://jscs.info/rule/disallowIdentifierNames) ```javascript // bad @@ -166,7 +174,8 @@ Other Style Guides (from Airbnb) }; ``` - - [3.3](#3.3) Use readable synonyms in place of reserved words. jscs: [`disallowIdentiferNames`](http://jscs.info/rule/disallowIdentifierNames) + + - [3.3](#objects--reserved-words-2) Use readable synonyms in place of reserved words. jscs: [`disallowIdentifierNames`](http://jscs.info/rule/disallowIdentifierNames) ```javascript // bad @@ -185,8 +194,8 @@ Other Style Guides (from Airbnb) }; ``` - - - [3.4](#3.4) Use computed property names when creating objects with dynamic property names. + + - [3.4](#es6-computed-properties) 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. @@ -211,8 +220,8 @@ Other Style Guides (from Airbnb) }; ``` - - - [3.5](#3.5) Use object method shorthand. eslint: [`object-shorthand`](http://eslint.org/docs/rules/object-shorthand.html) jscs: [`requireEnhancedObjectLiterals`](http://jscs.info/rule/requireEnhancedObjectLiterals) + + - [3.5](#es6-object-shorthand) Use object method shorthand. eslint: [`object-shorthand`](http://eslint.org/docs/rules/object-shorthand.html) jscs: [`requireEnhancedObjectLiterals`](http://jscs.info/rule/requireEnhancedObjectLiterals) ```javascript // bad @@ -234,8 +243,8 @@ Other Style Guides (from Airbnb) }; ``` - - - [3.6](#3.6) Use property value shorthand. eslint: [`object-shorthand`](http://eslint.org/docs/rules/object-shorthand.html) jscs: [`requireEnhancedObjectLiterals`](http://jscs.info/rule/requireEnhancedObjectLiterals) + + - [3.6](#es6-object-concise) Use property value shorthand. eslint: [`object-shorthand`](http://eslint.org/docs/rules/object-shorthand.html) jscs: [`requireEnhancedObjectLiterals`](http://jscs.info/rule/requireEnhancedObjectLiterals) > Why? It is shorter to write and descriptive. @@ -253,7 +262,8 @@ Other Style Guides (from Airbnb) }; ``` - - [3.7](#3.7) Group your shorthand properties at the beginning of your object declaration. + + - [3.7](#objects--grouped-shorthand) Group your shorthand properties at the beginning of your object declaration. > Why? It's easier to tell which properties are using the shorthand. @@ -282,7 +292,8 @@ Other Style Guides (from Airbnb) }; ``` - - [3.8](#3.8) Only quote properties that are invalid identifiers. eslint: [`quote-props`](http://eslint.org/docs/rules/quote-props.html) jscs: [`disallowQuotedKeysInObjects`](http://jscs.info/rule/disallowQuotedKeysInObjects) + + - [3.8](#objects-quoted-props) Only quote properties that are invalid identifiers. eslint: [`quote-props`](http://eslint.org/docs/rules/quote-props.html) jscs: [`disallowQuotedKeysInObjects`](http://jscs.info/rule/disallowQuotedKeysInObjects) > Why? In general we consider it subjectively easier to read. It improves syntax highlighting, and is also more easily optimized by many JS engines. @@ -328,7 +339,8 @@ Other Style Guides (from Airbnb) ## Arrays - - [4.1](#4.1) Use the literal syntax for array creation. eslint: [`no-array-constructor`](http://eslint.org/docs/rules/no-array-constructor.html) + + - [4.1](#arrays--literals) Use the literal syntax for array creation. eslint: [`no-array-constructor`](http://eslint.org/docs/rules/no-array-constructor.html) ```javascript // bad @@ -338,7 +350,8 @@ Other Style Guides (from Airbnb) const items = []; ``` - - [4.2](#4.2) Use Array#push instead of direct assignment to add items to an array. + + - [4.2](#arrays--push) Use Array#push instead of direct assignment to add items to an array. ```javascript const someStack = []; @@ -350,8 +363,8 @@ Other Style Guides (from Airbnb) someStack.push('abracadabra'); ``` - - - [4.3](#4.3) Use array spreads `...` to copy arrays. + + - [4.3](#es6-array-spreads) Use array spreads `...` to copy arrays. ```javascript // bad @@ -366,14 +379,17 @@ Other Style Guides (from Airbnb) // good const itemsCopy = [...items]; ``` - - [4.4](#4.4) To convert an array-like object to an array, use Array#from. + + + - [4.4](#arrays--from) To convert an array-like object to an array, use Array#from. ```javascript const foo = document.querySelectorAll('.foo'); 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) + + - [4.5](#arrays--callback-return) 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 @@ -425,7 +441,8 @@ Other Style Guides (from Airbnb) ## Destructuring - - [5.1](#5.1) Use object destructuring when accessing and using multiple properties of an object. jscs: [`requireObjectDestructuring`](http://jscs.info/rule/requireObjectDestructuring) + + - [5.1](#destructuring--object) Use object destructuring when accessing and using multiple properties of an object. jscs: [`requireObjectDestructuring`](http://jscs.info/rule/requireObjectDestructuring) > Why? Destructuring saves you from creating temporary references for those properties. @@ -450,7 +467,8 @@ Other Style Guides (from Airbnb) } ``` - - [5.2](#5.2) Use array destructuring. jscs: [`requireArrayDestructuring`](http://jscs.info/rule/requireArrayDestructuring) + + - [5.2](#destructuring--array) Use array destructuring. jscs: [`requireArrayDestructuring`](http://jscs.info/rule/requireArrayDestructuring) ```javascript const arr = [1, 2, 3, 4]; @@ -463,7 +481,8 @@ Other Style Guides (from Airbnb) const [first, second] = arr; ``` - - [5.3](#5.3) Use object destructuring for multiple return values, not array destructuring. jscs: [`disallowArrayDestructuringReturn`](http://jscs.info/rule/disallowArrayDestructuringReturn) + + - [5.3](#destructuring--object-over-array) Use object destructuring for multiple return values, not array destructuring. jscs: [`disallowArrayDestructuringReturn`](http://jscs.info/rule/disallowArrayDestructuringReturn) > Why? You can add new properties over time or change the order of things without breaking call sites. @@ -492,7 +511,8 @@ Other Style Guides (from Airbnb) ## Strings - - [6.1](#6.1) Use single quotes `''` for strings. eslint: [`quotes`](http://eslint.org/docs/rules/quotes.html) jscs: [`validateQuoteMarks`](http://jscs.info/rule/validateQuoteMarks) + + - [6.1](#strings--quotes) Use single quotes `''` for strings. eslint: [`quotes`](http://eslint.org/docs/rules/quotes.html) jscs: [`validateQuoteMarks`](http://jscs.info/rule/validateQuoteMarks) ```javascript // bad @@ -502,8 +522,11 @@ Other Style Guides (from Airbnb) const name = 'Capt. Janeway'; ``` - - [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). + + - [6.2](#strings--line-length) Strings that cause the line to go over 100 characters should be written across multiple lines using string concatenation. + + + - [6.3](#strings--concat-perf) 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 // bad @@ -521,8 +544,8 @@ Other Style Guides (from Airbnb) 'with this, you would get nowhere fast.'; ``` - - - [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) + + - [6.4](#es6-template-literals) 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. @@ -547,14 +570,17 @@ Other Style Guides (from Airbnb) return `How are you, ${name}?`; } ``` - - [6.5](#6.5) Never use `eval()` on a string, it opens too many vulnerabilities. + + + - [6.5](#strings--eval) Never use `eval()` on a string, it opens too many vulnerabilities. **[⬆ back to top](#table-of-contents)** ## Functions - - [7.1](#7.1) Use function declarations instead of function expressions. jscs: [`requireFunctionDeclarations`](http://jscs.info/rule/requireFunctionDeclarations) + + - [7.1](#functions--declarations) Use function declarations instead of function expressions. jscs: [`requireFunctionDeclarations`](http://jscs.info/rule/requireFunctionDeclarations) > 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. @@ -568,7 +594,8 @@ Other Style Guides (from Airbnb) } ``` - - [7.2](#7.2) Immediately invoked function expressions: eslint: [`wrap-iife`](http://eslint.org/docs/rules/wrap-iife.html) jscs: [`requireParenthesesAroundIIFE`](http://jscs.info/rule/requireParenthesesAroundIIFE) + + - [7.2](#functions--iife) Immediately invoked function expressions: eslint: [`wrap-iife`](http://eslint.org/docs/rules/wrap-iife.html) jscs: [`requireParenthesesAroundIIFE`](http://jscs.info/rule/requireParenthesesAroundIIFE) > Why? An immediately invoked function expression is a single unit - wrapping both it, and its invocation parens, in parens, cleanly expresses this. Note that in a world with modules everywhere, you almost never need an IIFE. @@ -579,9 +606,11 @@ Other Style Guides (from Airbnb) }()); ``` - - [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. eslint: [`no-loop-func`](http://eslint.org/docs/rules/no-loop-func.html) + + - [7.3](#functions--in-blocks) 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. eslint: [`no-loop-func`](http://eslint.org/docs/rules/no-loop-func.html) - - [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). + + - [7.4](#functions--note-on-blocks) **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 // bad @@ -600,7 +629,8 @@ Other Style Guides (from Airbnb) } ``` - - [7.5](#7.5) Never name a parameter `arguments`. This will take precedence over the `arguments` object that is given to every function scope. + + - [7.5](#functions--arguments-shadow) Never name a parameter `arguments`. This will take precedence over the `arguments` object that is given to every function scope. ```javascript // bad @@ -614,10 +644,10 @@ Other Style Guides (from Airbnb) } ``` - - - [7.6](#7.6) Never use `arguments`, opt to use rest syntax `...` instead. [`prefer-rest-params`](http://eslint.org/docs/rules/prefer-rest-params) + + - [7.6](#es6-rest) 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`. + > Why? `...` is explicit about which arguments you want pulled. Plus, rest arguments are a real Array, and not merely Array-like like `arguments`. ```javascript // bad @@ -632,8 +662,8 @@ Other Style Guides (from Airbnb) } ``` - - - [7.7](#7.7) Use default parameter syntax rather than mutating function arguments. + + - [7.7](#es6-default-parameters) Use default parameter syntax rather than mutating function arguments. ```javascript // really bad @@ -659,7 +689,8 @@ Other Style Guides (from Airbnb) } ``` - - [7.8](#7.8) Avoid side effects with default parameters. + + - [7.8](#functions--default-side-effects) Avoid side effects with default parameters. > Why? They are confusing to reason about. @@ -675,7 +706,8 @@ Other Style Guides (from Airbnb) count(); // 3 ``` - - [7.9](#7.9) Always put default parameters last. + + - [7.9](#functions--defaults-last) Always put default parameters last. ```javascript // bad @@ -689,7 +721,8 @@ Other Style Guides (from Airbnb) } ``` - - [7.10](#7.10) Never use the Function constructor to create a new function. + + - [7.10](#functions--constructor) 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. @@ -701,7 +734,8 @@ Other Style Guides (from Airbnb) var subtract = Function('a', 'b', 'return a - b'); ``` - - [7.11](#7.11) Spacing in a function signature. + + - [7.11](#functions--signature-spacing) 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. @@ -716,7 +750,8 @@ Other Style Guides (from Airbnb) const y = function a() {}; ``` - - [7.12](#7.12) Never mutate parameters. eslint: [`no-param-reassign`](http://eslint.org/docs/rules/no-param-reassign.html) + + - [7.12](#functions--mutate-params) Never mutate parameters. eslint: [`no-param-reassign`](http://eslint.org/docs/rules/no-param-reassign.html) > Why? Manipulating objects passed in as parameters can cause unwanted variable side effects in the original caller. @@ -732,7 +767,8 @@ Other Style Guides (from Airbnb) }; ``` - - [7.13](#7.13) Never reassign parameters. eslint: [`no-param-reassign`](http://eslint.org/docs/rules/no-param-reassign.html) + + - [7.13](#functions--reassign-params) Never reassign parameters. eslint: [`no-param-reassign`](http://eslint.org/docs/rules/no-param-reassign.html) > Why? Reassigning parameters can lead to unexpected behavior, especially when accessing the `arguments` object. It can also cause optimization issues, especially in V8. @@ -759,7 +795,8 @@ Other Style Guides (from Airbnb) ## Arrow Functions - - [8.1](#8.1) When you must use function expressions (as when passing an anonymous function), use arrow function notation. eslint: [`prefer-arrow-callback`](http://eslint.org/docs/rules/prefer-arrow-callback.html), [`arrow-spacing`](http://eslint.org/docs/rules/arrow-spacing.html) jscs: [`requireArrowFunctions`](http://jscs.info/rule/requireArrowFunctions) + + - [8.1](#arrows--use-them) When you must use function expressions (as when passing an anonymous function), use arrow function notation. eslint: [`prefer-arrow-callback`](http://eslint.org/docs/rules/prefer-arrow-callback.html), [`arrow-spacing`](http://eslint.org/docs/rules/arrow-spacing.html) jscs: [`requireArrowFunctions`](http://jscs.info/rule/requireArrowFunctions) > 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. @@ -779,7 +816,8 @@ Other Style Guides (from Airbnb) }); ``` - - [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. eslint: [`arrow-parens`](http://eslint.org/docs/rules/arrow-parens.html), [`arrow-body-style`](http://eslint.org/docs/rules/arrow-body-style.html) jscs: [`disallowParenthesesAroundArrowParam`](http://jscs.info/rule/disallowParenthesesAroundArrowParam), [`requireShorthandArrowFunctions`](http://jscs.info/rule/requireShorthandArrowFunctions) + + - [8.2](#arrows--implicit-return) 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. eslint: [`arrow-parens`](http://eslint.org/docs/rules/arrow-parens.html), [`arrow-body-style`](http://eslint.org/docs/rules/arrow-body-style.html) jscs: [`disallowParenthesesAroundArrowParam`](http://jscs.info/rule/disallowParenthesesAroundArrowParam), [`requireShorthandArrowFunctions`](http://jscs.info/rule/requireShorthandArrowFunctions) > Why? Syntactic sugar. It reads well when multiple functions are chained together. @@ -802,7 +840,8 @@ Other Style Guides (from Airbnb) }); ``` - - [8.3](#8.3) In case the expression spans over multiple lines, wrap it in parentheses for better readability. + + - [8.3](#arrows--paren-wrap) 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. @@ -820,8 +859,8 @@ Other Style Guides (from Airbnb) )); ``` - - - [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. eslint: [`arrow-parens`](http://eslint.org/docs/rules/arrow-parens.html) jscs: [`disallowParenthesesAroundArrowParam`](http://jscs.info/rule/disallowParenthesesAroundArrowParam) + + - [8.4](#arrows--one-arg-parens) If your function takes a single argument and doesn’t use braces, omit the parentheses. Otherwise, always include parentheses around arguments. eslint: [`arrow-parens`](http://eslint.org/docs/rules/arrow-parens.html) jscs: [`disallowParenthesesAroundArrowParam`](http://jscs.info/rule/disallowParenthesesAroundArrowParam) > Why? Less visual clutter. @@ -851,7 +890,8 @@ Other Style Guides (from Airbnb) }); ``` - - [8.5](#8.5) Avoid confusing arrow function syntax (`=>`) with comparison operators (`<=`, `>=`). eslint: [`no-confusing-arrow`](http://eslint.org/docs/rules/no-confusing-arrow) + + - [8.5](#arrows--confusing) Avoid confusing arrow function syntax (`=>`) with comparison operators (`<=`, `>=`). eslint: [`no-confusing-arrow`](http://eslint.org/docs/rules/no-confusing-arrow) ```js // bad @@ -861,7 +901,7 @@ Other Style Guides (from Airbnb) const itemHeight = (item) => item.height > 256 ? item.largeSize : item.smallSize; // good - const itemHeight = item => { return item.height > 256 ? item.largeSize : item.smallSize; } + const itemHeight = (item) => { return item.height > 256 ? item.largeSize : item.smallSize; } ``` **[⬆ back to top](#table-of-contents)** @@ -869,36 +909,38 @@ Other Style Guides (from Airbnb) ## Constructors - - [9.1](#9.1) Always use `class`. Avoid manipulating `prototype` directly. + + - [9.1](#constructors--use-class) Always use `class`. Avoid manipulating `prototype` directly. > Why? `class` syntax is more concise and easier to reason about. ```javascript // bad function Queue(contents = []) { - this._queue = [...contents]; + this.queue = [...contents]; } Queue.prototype.pop = function () { - const value = this._queue[0]; - this._queue.splice(0, 1); + const value = this.queue[0]; + this.queue.splice(0, 1); return value; - } + }; // good class Queue { constructor(contents = []) { - this._queue = [...contents]; + this.queue = [...contents]; } pop() { - const value = this._queue[0]; - this._queue.splice(0, 1); + const value = this.queue[0]; + this.queue.splice(0, 1); return value; } } ``` - - [9.2](#9.2) Use `extends` for inheritance. + + - [9.2](#constructors--extends) Use `extends` for inheritance. > Why? It is a built-in way to inherit prototype functionality without breaking `instanceof`. @@ -921,7 +963,8 @@ Other Style Guides (from Airbnb) } ``` - - [9.3](#9.3) Methods can return `this` to help with method chaining. + + - [9.3](#constructors--chaining) Methods can return `this` to help with method chaining. ```javascript // bad @@ -958,7 +1001,8 @@ Other Style Guides (from Airbnb) ``` - - [9.4](#9.4) It's okay to write a custom toString() method, just make sure it works successfully and causes no side effects. + + - [9.4](#constructors--tostring) It's okay to write a custom toString() method, just make sure it works successfully and causes no side effects. ```javascript class Jedi { @@ -976,7 +1020,8 @@ Other Style Guides (from Airbnb) } ``` - - [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) + + - [9.5](#constructors--no-useless) 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 @@ -1009,7 +1054,8 @@ Other Style Guides (from Airbnb) ## Modules - - [10.1](#10.1) Always use modules (`import`/`export`) over a non-standard module system. You can always transpile to your preferred module system. + + - [10.1](#modules--use-them) 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. @@ -1027,7 +1073,8 @@ Other Style Guides (from Airbnb) export default es6; ``` - - [10.2](#10.2) Do not use wildcard imports. + + - [10.2](#modules--no-wildcard) Do not use wildcard imports. > Why? This makes sure you have a single default export. @@ -1039,7 +1086,8 @@ Other Style Guides (from Airbnb) import AirbnbStyleGuide from './AirbnbStyleGuide'; ``` - - [10.3](#10.3) And do not export directly from an import. + + - [10.3](#modules--no-export-from-import) 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. @@ -1058,7 +1106,8 @@ Other Style Guides (from Airbnb) ## Iterators and Generators - - [11.1](#11.1) Don't use iterators. Prefer JavaScript's higher-order functions like `map()` and `reduce()` instead of loops like `for-of`. eslint: [`no-iterator`](http://eslint.org/docs/rules/no-iterator.html) + + - [11.1](#iterators--nope) Don't use iterators. Prefer JavaScript's higher-order functions like `map()` and `reduce()` instead of loops like `for-of`. eslint: [`no-iterator`](http://eslint.org/docs/rules/no-iterator.html) > Why? This enforces our immutable rule. Dealing with pure functions that return values is easier to reason about than side effects. @@ -1083,7 +1132,8 @@ Other Style Guides (from Airbnb) sum === 15; ``` - - [11.2](#11.2) Don't use generators for now. + + - [11.2](#generators--nope) Don't use generators for now. > Why? They don't transpile well to ES5. @@ -1092,7 +1142,8 @@ Other Style Guides (from Airbnb) ## Properties - - [12.1](#12.1) Use dot notation when accessing properties. eslint: [`dot-notation`](http://eslint.org/docs/rules/dot-notation.html) jscs: [`requireDotNotation`](http://jscs.info/rule/requireDotNotation) + + - [12.1](#properties--dot) Use dot notation when accessing properties. eslint: [`dot-notation`](http://eslint.org/docs/rules/dot-notation.html) jscs: [`requireDotNotation`](http://jscs.info/rule/requireDotNotation) ```javascript const luke = { @@ -1107,7 +1158,8 @@ Other Style Guides (from Airbnb) const isJedi = luke.jedi; ``` - - [12.2](#12.2) Use subscript notation `[]` when accessing properties with a variable. + + - [12.2](#properties--bracket) Use bracket notation `[]` when accessing properties with a variable. ```javascript const luke = { @@ -1127,7 +1179,8 @@ Other Style Guides (from Airbnb) ## Variables - - [13.1](#13.1) Always use `const` to declare variables. Not doing so will result in global variables. We want to avoid polluting the global namespace. Captain Planet warned us of that. + + - [13.1](#variables--const) Always use `const` to declare variables. Not doing so will result in global variables. We want to avoid polluting the global namespace. Captain Planet warned us of that. ```javascript // bad @@ -1137,9 +1190,10 @@ Other Style Guides (from Airbnb) const superPower = new SuperPower(); ``` - - [13.2](#13.2) Use one `const` declaration per variable. eslint: [`one-var`](http://eslint.org/docs/rules/one-var.html) jscs: [`disallowMultipleVarDecl`](http://jscs.info/rule/disallowMultipleVarDecl) + + - [13.2](#variables--one-const) Use one `const` declaration per variable. eslint: [`one-var`](http://eslint.org/docs/rules/one-var.html) jscs: [`disallowMultipleVarDecl`](http://jscs.info/rule/disallowMultipleVarDecl) - > 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. + > 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. You can also step through each declaration with the debugger, instead of jumping through all of them at once. ```javascript // bad @@ -1159,7 +1213,8 @@ Other Style Guides (from Airbnb) const dragonball = 'z'; ``` - - [13.3](#13.3) Group all your `const`s and then group all your `let`s. + + - [13.3](#variables--const-let-group) 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. @@ -1184,7 +1239,8 @@ Other Style Guides (from Airbnb) let length; ``` - - [13.4](#13.4) Assign variables where you need them, but place them in a reasonable place. + + - [13.4](#variables--define-where-used) Assign variables where you need them, but place them in a reasonable place. > Why? `let` and `const` are block scoped and not function scoped. @@ -1227,7 +1283,8 @@ Other Style Guides (from Airbnb) ## Hoisting - - [14.1](#14.1) `var` declarations get hoisted to the top of their scope, their assignment does not. `const` and `let` declarations are blessed with a new concept called [Temporal Dead Zones (TDZ)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let#Temporal_dead_zone_and_errors_with_let). It's important to know why [typeof is no longer safe](http://es-discourse.com/t/why-typeof-is-no-longer-safe/15). + + - [14.1](#hoisting--about) `var` declarations get hoisted to the top of their scope, their assignment does not. `const` and `let` declarations are blessed with a new concept called [Temporal Dead Zones (TDZ)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let#Temporal_dead_zone_and_errors_with_let). It's important to know why [typeof is no longer safe](http://es-discourse.com/t/why-typeof-is-no-longer-safe/15). ```javascript // we know this wouldn't work (assuming there @@ -1262,7 +1319,8 @@ Other Style Guides (from Airbnb) } ``` - - [14.2](#14.2) Anonymous function expressions hoist their variable name, but not the function assignment. + + - [14.2](#hoisting--anon-expressions) Anonymous function expressions hoist their variable name, but not the function assignment. ```javascript function example() { @@ -1276,7 +1334,8 @@ Other Style Guides (from Airbnb) } ``` - - [14.3](#14.3) Named function expressions hoist the variable name, not the function name or the function body. + + - [14.3](#hoisting--named-expresions) Named function expressions hoist the variable name, not the function name or the function body. ```javascript function example() { @@ -1304,7 +1363,8 @@ Other Style Guides (from Airbnb) } ``` - - [14.4](#14.4) Function declarations hoist their name and the function body. + + - [14.4](#hoisting--declarations) Function declarations hoist their name and the function body. ```javascript function example() { @@ -1323,9 +1383,11 @@ Other Style Guides (from Airbnb) ## Comparison Operators & Equality - - [15.1](#15.1) Use `===` and `!==` over `==` and `!=`. eslint: [`eqeqeq`](http://eslint.org/docs/rules/eqeqeq.html) + + - [15.1](#comparison--eqeqeq) Use `===` and `!==` over `==` and `!=`. eslint: [`eqeqeq`](http://eslint.org/docs/rules/eqeqeq.html) - - [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: + + - [15.2](#comparison--if) Conditional statements such as the `if` statement evaluate their expression using coercion with the `ToBoolean` abstract method and always follow these simple rules: + **Objects** evaluate to **true** + **Undefined** evaluates to **false** @@ -1341,7 +1403,8 @@ Other Style Guides (from Airbnb) } ``` - - [15.3](#15.3) Use shortcuts. + + - [15.3](#comparison--shortcuts) Use shortcuts. ```javascript // bad @@ -1365,8 +1428,11 @@ Other Style Guides (from Airbnb) } ``` - - [15.4](#15.4) For more information see [Truth Equality and JavaScript](http://javascriptweblog.wordpress.com/2011/02/07/truth-equality-and-javascript/#more-2108) by Angus Croll. - - [15.5](#15.5) Use braces to create blocks in `case` and `default` clauses that contain lexical declarations (e.g. `let`, `const`, `function`, and `class`). + + - [15.4](#comparison--moreinfo) For more information see [Truth Equality and JavaScript](http://javascriptweblog.wordpress.com/2011/02/07/truth-equality-and-javascript/#more-2108) by Angus Croll. + + + - [15.5](#comparison--switch-blocks) Use braces to create blocks in `case` and `default` clauses that contain lexical declarations (e.g. `let`, `const`, `function`, and `class`). > Why? Lexical declarations are visible in the entire `switch` block but only get initialized when assigned, which only happens when its `case` is reached. This causes problems when multiple `case` clauses attempt to define the same thing. @@ -1411,7 +1477,8 @@ Other Style Guides (from Airbnb) } ``` - - [15.6](#15.6) Ternaries should not be nested and generally be single line expressions. + + - [15.6](#comparison--nested-ternaries) Ternaries should not be nested and generally be single line expressions. eslint rules: [`no-nested-ternary`](http://eslint.org/docs/rules/no-nested-ternary.html). @@ -1434,7 +1501,8 @@ Other Style Guides (from Airbnb) const foo = maybe1 > maybe2 ? 'bar' : maybeNull; ``` - - [15.7](#15.7) Avoid unneeded ternary statements. + + - [15.7](#comparison--unneeded-ternary) Avoid unneeded ternary statements. eslint rules: [`no-unneeded-ternary`](http://eslint.org/docs/rules/no-unneeded-ternary.html). @@ -1455,7 +1523,8 @@ Other Style Guides (from Airbnb) ## Blocks - - [16.1](#16.1) Use braces with all multi-line blocks. + + - [16.1](#blocks--braces) Use braces with all multi-line blocks. ```javascript // bad @@ -1479,8 +1548,8 @@ Other Style Guides (from Airbnb) } ``` - - [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: [`brace-style`](http://eslint.org/docs/rules/brace-style.html) jscs: [`disallowNewlineBeforeBlockStatements`](http://jscs.info/rule/disallowNewlineBeforeBlockStatements) + + - [16.2](#blocks--cuddled-elses) 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: [`brace-style`](http://eslint.org/docs/rules/brace-style.html) jscs: [`disallowNewlineBeforeBlockStatements`](http://jscs.info/rule/disallowNewlineBeforeBlockStatements) ```javascript // bad @@ -1507,7 +1576,8 @@ Other Style Guides (from Airbnb) ## Comments - - [17.1](#17.1) Use `/** ... */` for multi-line comments. Include a description, specify types and values for all parameters and return values. + + - [17.1](#comments--multiline) Use `/** ... */` for multi-line comments. Include a description, specify types and values for all parameters and return values. ```javascript // bad @@ -1539,7 +1609,8 @@ Other Style Guides (from Airbnb) } ``` - - [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. + + - [17.2](#comments--singleline) 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 @@ -1577,9 +1648,11 @@ Other Style Guides (from Airbnb) } ``` - - [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`. + + - [17.3](#comments--actionitems) 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`. - - [17.4](#17.4) Use `// FIXME:` to annotate problems. + + - [17.4](#comments--fixme) Use `// FIXME:` to annotate problems. ```javascript class Calculator extends Abacus { @@ -1592,7 +1665,8 @@ Other Style Guides (from Airbnb) } ``` - - [17.5](#17.5) Use `// TODO:` to annotate solutions to problems. + + - [17.5](#comments--todo) Use `// TODO:` to annotate solutions to problems. ```javascript class Calculator extends Abacus { @@ -1610,7 +1684,8 @@ Other Style Guides (from Airbnb) ## Whitespace - - [18.1](#18.1) Use soft tabs set to 2 spaces. eslint: [`indent`](http://eslint.org/docs/rules/indent.html) jscs: [`validateIndentation`](http://jscs.info/rule/validateIndentation) + + - [18.1](#whitespace--spaces) Use soft tabs set to 2 spaces. eslint: [`indent`](http://eslint.org/docs/rules/indent.html) jscs: [`validateIndentation`](http://jscs.info/rule/validateIndentation) ```javascript // bad @@ -1629,7 +1704,8 @@ Other Style Guides (from Airbnb) } ``` - - [18.2](#18.2) Place 1 space before the leading brace. eslint: [`space-before-blocks`](http://eslint.org/docs/rules/space-before-blocks.html) jscs: [`requireSpaceBeforeBlockStatements`](http://jscs.info/rule/requireSpaceBeforeBlockStatements) + + - [18.2](#whitespace--before-blocks) Place 1 space before the leading brace. eslint: [`space-before-blocks`](http://eslint.org/docs/rules/space-before-blocks.html) jscs: [`requireSpaceBeforeBlockStatements`](http://jscs.info/rule/requireSpaceBeforeBlockStatements) ```javascript // bad @@ -1655,7 +1731,8 @@ Other Style Guides (from Airbnb) }); ``` - - [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: [`space-after-keywords`](http://eslint.org/docs/rules/space-after-keywords.html), [`space-before-keywords`](http://eslint.org/docs/rules/space-before-keywords.html) jscs: [`requireSpaceAfterKeywords`](http://jscs.info/rule/requireSpaceAfterKeywords) + + - [18.3](#whitespace--around-keywords) 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: [`space-after-keywords`](http://eslint.org/docs/rules/space-after-keywords.html), [`space-before-keywords`](http://eslint.org/docs/rules/space-before-keywords.html) jscs: [`requireSpaceAfterKeywords`](http://jscs.info/rule/requireSpaceAfterKeywords) ```javascript // bad @@ -1679,7 +1756,8 @@ Other Style Guides (from Airbnb) } ``` - - [18.4](#18.4) Set off operators with spaces. eslint: [`space-infix-ops`](http://eslint.org/docs/rules/space-infix-ops.html) jscs: [`requireSpaceBeforeBinaryOperators`](http://jscs.info/rule/requireSpaceBeforeBinaryOperators), [`requireSpaceAfterBinaryOperators`](http://jscs.info/rule/requireSpaceAfterBinaryOperators) + + - [18.4](#whitespace--infix-ops) Set off operators with spaces. eslint: [`space-infix-ops`](http://eslint.org/docs/rules/space-infix-ops.html) jscs: [`requireSpaceBeforeBinaryOperators`](http://jscs.info/rule/requireSpaceBeforeBinaryOperators), [`requireSpaceAfterBinaryOperators`](http://jscs.info/rule/requireSpaceAfterBinaryOperators) ```javascript // bad @@ -1689,7 +1767,8 @@ Other Style Guides (from Airbnb) const x = y + 5; ``` - - [18.5](#18.5) End files with a single newline character. + + - [18.5](#whitespace--newline-at-end) End files with a single newline character. ```javascript // bad @@ -1713,7 +1792,8 @@ Other Style Guides (from Airbnb) })(this);↵ ``` - - [18.6](#18.6) Use indentation when making long method chains (more than 2 method chains). Use a leading dot, which + + - [18.6](#whitespace--chains) 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 @@ -1756,7 +1836,8 @@ Other Style Guides (from Airbnb) 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) + + - [18.7](#whitespace--after-blocks) Leave a blank line after blocks and before the next statement. jscs: [`requirePaddingNewLinesAfterBlocks`](http://jscs.info/rule/requirePaddingNewLinesAfterBlocks) ```javascript // bad @@ -1813,7 +1894,8 @@ Other Style Guides (from Airbnb) return arr; ``` - - [18.8](#18.8) Do not pad your blocks with blank lines. eslint: [`padded-blocks`](http://eslint.org/docs/rules/padded-blocks.html) jscs: [`disallowPaddingNewlinesInBlocks`](http://jscs.info/rule/disallowPaddingNewlinesInBlocks) + + - [18.8](#whitespace--padded-blocks) Do not pad your blocks with blank lines. eslint: [`padded-blocks`](http://eslint.org/docs/rules/padded-blocks.html) jscs: [`disallowPaddingNewlinesInBlocks`](http://jscs.info/rule/disallowPaddingNewlinesInBlocks) ```javascript // bad @@ -1845,7 +1927,8 @@ Other Style Guides (from Airbnb) } ``` - - [18.9](#18.9) Do not add spaces inside parentheses. eslint: [`space-in-parens`](http://eslint.org/docs/rules/space-in-parens.html) jscs: [`disallowSpacesInsideParentheses`](http://jscs.info/rule/disallowSpacesInsideParentheses) + + - [18.9](#whitespace--in-parens) Do not add spaces inside parentheses. eslint: [`space-in-parens`](http://eslint.org/docs/rules/space-in-parens.html) jscs: [`disallowSpacesInsideParentheses`](http://jscs.info/rule/disallowSpacesInsideParentheses) ```javascript // bad @@ -1869,7 +1952,8 @@ Other Style Guides (from Airbnb) } ``` - - [18.10](#18.10) Do not add spaces inside brackets. eslint: [`array-bracket-spacing`](http://eslint.org/docs/rules/array-bracket-spacing.html) jscs: [`disallowSpacesInsideArrayBrackets`](http://jscs.info/rule/disallowSpacesInsideArrayBrackets) + + - [18.10](#whitespace--in-brackets) Do not add spaces inside brackets. eslint: [`array-bracket-spacing`](http://eslint.org/docs/rules/array-bracket-spacing.html) jscs: [`disallowSpacesInsideArrayBrackets`](http://jscs.info/rule/disallowSpacesInsideArrayBrackets) ```javascript // bad @@ -1881,7 +1965,8 @@ Other Style Guides (from Airbnb) console.log(foo[0]); ``` - - [18.11](#18.11) Add spaces inside curly braces. eslint: [`object-curly-spacing`](http://eslint.org/docs/rules/object-curly-spacing.html) jscs: [`disallowSpacesInsideObjectBrackets`](http://jscs.info/rule/disallowSpacesInsideObjectBrackets) + + - [18.11](#whitespace--in-braces) Add spaces inside curly braces. eslint: [`object-curly-spacing`](http://eslint.org/docs/rules/object-curly-spacing.html) jscs: [`disallowSpacesInsideObjectBrackets`](http://jscs.info/rule/disallowSpacesInsideObjectBrackets) ```javascript // bad @@ -1891,7 +1976,8 @@ Other Style Guides (from Airbnb) const foo = { clark: 'kent' }; ``` - - [18.12](#18.12) Avoid having lines of code that are longer than 100 characters (including whitespace). eslint: [`max-len`](http://eslint.org/docs/rules/max-len.html) jscs: [`maximumLineLength`](http://jscs.info/rule/maximumLineLength) + + - [18.12](#whitespace--max-len) Avoid having lines of code that are longer than 100 characters (including whitespace). eslint: [`max-len`](http://eslint.org/docs/rules/max-len.html) jscs: [`maximumLineLength`](http://jscs.info/rule/maximumLineLength) > Why? This ensures readability and maintainability. @@ -1920,7 +2006,8 @@ Other Style Guides (from Airbnb) ## Commas - - [19.1](#19.1) Leading commas: **Nope.** eslint: [`comma-style`](http://eslint.org/docs/rules/comma-style.html) jscs: [`requireCommaBeforeLineBreak`](http://jscs.info/rule/requireCommaBeforeLineBreak) + + - [19.1](#commas--leading-trailing) Leading commas: **Nope.** eslint: [`comma-style`](http://eslint.org/docs/rules/comma-style.html) jscs: [`requireCommaBeforeLineBreak`](http://jscs.info/rule/requireCommaBeforeLineBreak) ```javascript // bad @@ -1954,7 +2041,8 @@ Other Style Guides (from Airbnb) }; ``` - - [19.2](#19.2) Additional trailing comma: **Yup.** eslint: [`comma-dangle`](http://eslint.org/docs/rules/comma-dangle.html) jscs: [`requireTrailingComma`](http://jscs.info/rule/requireTrailingComma) + + - [19.2](#commas--dangling) Additional trailing comma: **Yup.** eslint: [`comma-dangle`](http://eslint.org/docs/rules/comma-dangle.html) jscs: [`requireTrailingComma`](http://jscs.info/rule/requireTrailingComma) > 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. @@ -2002,7 +2090,8 @@ Other Style Guides (from Airbnb) ## Semicolons - - [20.1](#20.1) **Yup.** eslint: [`semi`](http://eslint.org/docs/rules/semi.html) jscs: [`requireSemicolons`](http://jscs.info/rule/requireSemicolons) + + - [20.1](#20.1) **Yup.** eslint: [`semi`](http://eslint.org/docs/rules/semi.html) jscs: [`requireSemicolons`](http://jscs.info/rule/requireSemicolons) ```javascript // bad @@ -2031,20 +2120,27 @@ Other Style Guides (from Airbnb) ## Type Casting & Coercion - - [21.1](#21.1) Perform type coercion at the beginning of the statement. - - [21.2](#21.2) Strings: + + - [21.1](#coercion--explicit) Perform type coercion at the beginning of the statement. + + + - [21.2](#coercion--strings) Strings: ```javascript // => this.reviewScore = 9; // bad - const totalScore = this.reviewScore + ''; + const totalScore = this.reviewScore + ''; // invokes this.reviewScore.valueOf() + + // bad + const totalScore = this.reviewScore.toString(); // isn't guaranteed to return a string // good const totalScore = String(this.reviewScore); ``` - - [21.3](#21.3) Numbers: Use `Number` for type casting and `parseInt` always with a radix for parsing strings. eslint: [`radix`](http://eslint.org/docs/rules/radix) + + - [21.3](#coercion--numbers) Numbers: Use `Number` for type casting and `parseInt` always with a radix for parsing strings. eslint: [`radix`](http://eslint.org/docs/rules/radix) ```javascript const inputValue = '4'; @@ -2068,7 +2164,8 @@ Other Style Guides (from Airbnb) const val = parseInt(inputValue, 10); ``` - - [21.4](#21.4) If for whatever reason you are doing something wild and `parseInt` is your bottleneck and need to use Bitshift for [performance reasons](http://jsperf.com/coercion-vs-casting/3), leave a comment explaining why and what you're doing. + + - [21.4](#coercion--comment-deviations) If for whatever reason you are doing something wild and `parseInt` is your bottleneck and need to use Bitshift for [performance reasons](http://jsperf.com/coercion-vs-casting/3), leave a comment explaining why and what you're doing. ```javascript // good @@ -2080,7 +2177,8 @@ Other Style Guides (from Airbnb) const val = inputValue >> 0; ``` - - [21.5](#21.5) **Note:** Be careful when using bitshift operations. Numbers are represented as [64-bit values](http://es5.github.io/#x4.3.19), but bitshift operations always return a 32-bit integer ([source](http://es5.github.io/#x11.7)). Bitshift can lead to unexpected behavior for integer values larger than 32 bits. [Discussion](https://github.com/airbnb/javascript/issues/109). Largest signed 32-bit Int is 2,147,483,647: + + - [21.5](#coercion--bitwise) **Note:** Be careful when using bitshift operations. Numbers are represented as [64-bit values](http://es5.github.io/#x4.3.19), but bitshift operations always return a 32-bit integer ([source](http://es5.github.io/#x11.7)). Bitshift can lead to unexpected behavior for integer values larger than 32 bits. [Discussion](https://github.com/airbnb/javascript/issues/109). Largest signed 32-bit Int is 2,147,483,647: ```javascript 2147483647 >> 0 //=> 2147483647 @@ -2088,7 +2186,8 @@ Other Style Guides (from Airbnb) 2147483649 >> 0 //=> -2147483647 ``` - - [21.6](#21.6) Booleans: + + - [21.6](#coercion--booleans) Booleans: ```javascript const age = 0; @@ -2108,7 +2207,8 @@ Other Style Guides (from Airbnb) ## Naming Conventions - - [22.1](#22.1) Avoid single letter names. Be descriptive with your naming. + + - [22.1](#naming--descriptive) Avoid single letter names. Be descriptive with your naming. ```javascript // bad @@ -2122,7 +2222,8 @@ Other Style Guides (from Airbnb) } ``` - - [22.2](#22.2) Use camelCase when naming objects, functions, and instances. eslint: [`camelcase`](http://eslint.org/docs/rules/camelcase.html) jscs: [`requireCamelCaseOrUpperCaseIdentifiers`](http://jscs.info/rule/requireCamelCaseOrUpperCaseIdentifiers) + + - [22.2](#naming--camelCase) Use camelCase when naming objects, functions, and instances. eslint: [`camelcase`](http://eslint.org/docs/rules/camelcase.html) jscs: [`requireCamelCaseOrUpperCaseIdentifiers`](http://jscs.info/rule/requireCamelCaseOrUpperCaseIdentifiers) ```javascript // bad @@ -2135,7 +2236,8 @@ Other Style Guides (from Airbnb) function thisIsMyFunction() {} ``` - - [22.3](#22.3) Use PascalCase when naming constructors or classes. eslint: [`new-cap`](http://eslint.org/docs/rules/new-cap.html) jscs: [`requireCapitalizedConstructors`](http://jscs.info/rule/requireCapitalizedConstructors) + + - [22.3](#naming--PascalCase) Use PascalCase only when naming constructors or classes. eslint: [`new-cap`](http://eslint.org/docs/rules/new-cap.html) jscs: [`requireCapitalizedConstructors`](http://jscs.info/rule/requireCapitalizedConstructors) ```javascript // bad @@ -2159,7 +2261,8 @@ Other Style Guides (from Airbnb) }); ``` - - [22.4](#22.4) Use a leading underscore `_` when naming private properties. eslint: [`no-underscore-dangle`](http://eslint.org/docs/rules/no-underscore-dangle.html) jscs: [`disallowDanglingUnderscores`](http://jscs.info/rule/disallowDanglingUnderscores) + + - [22.4](#naming--leading-underscore) Use a leading underscore `_` when naming private properties. eslint: [`no-underscore-dangle`](http://eslint.org/docs/rules/no-underscore-dangle.html) jscs: [`disallowDanglingUnderscores`](http://jscs.info/rule/disallowDanglingUnderscores) ```javascript // bad @@ -2170,7 +2273,8 @@ Other Style Guides (from Airbnb) this._firstName = 'Panda'; ``` - - [22.5](#22.5) Don't save references to `this`. Use arrow functions or Function#bind. jscs: [`disallowNodeTypes`](http://jscs.info/rule/disallowNodeTypes) + + - [22.5](#naming--self-this) Don't save references to `this`. Use arrow functions or Function#bind. jscs: [`disallowNodeTypes`](http://jscs.info/rule/disallowNodeTypes) ```javascript // bad @@ -2197,7 +2301,8 @@ Other Style Guides (from Airbnb) } ``` - - [22.6](#22.6) If your file exports a single class, your filename should be exactly the name of the class. + + - [22.6](#naming--filename-matches-export) If your file exports a single class, your filename should be exactly the name of the class. ```javascript // file contents @@ -2217,7 +2322,8 @@ Other Style Guides (from Airbnb) import CheckBox from './CheckBox'; ``` - - [22.7](#22.7) Use camelCase when you export-default a function. Your filename should be identical to your function's name. + + - [22.7](#naming--camelCase-default-export) Use camelCase when you export-default a function. Your filename should be identical to your function's name. ```javascript function makeStyleGuide() { @@ -2226,7 +2332,8 @@ Other Style Guides (from Airbnb) export default makeStyleGuide; ``` - - [22.8](#22.8) Use PascalCase when you export a singleton / function library / bare object. + + - [22.8](#naming--PascalCase-singleton) Use PascalCase when you export a singleton / function library / bare object. ```javascript const AirbnbStyleGuide = { @@ -2243,8 +2350,11 @@ Other Style Guides (from Airbnb) ## Accessors - - [23.1](#23.1) Accessor functions for properties are not required. - - [23.2](#23.2) Do not use JavaScript getters/setters as they cause unexpected side effects and are harder to test, maintain, and reason about. Instead, if you do make accessor functions, use getVal() and setVal('hello'). + + - [23.1](#accessors--not-required) Accessor functions for properties are not required. + + + - [23.2](#accessors--no-getters-setters) Do not use JavaScript getters/setters as they cause unexpected side effects and are harder to test, maintain, and reason about. Instead, if you do make accessor functions, use getVal() and setVal('hello'). ```javascript // bad @@ -2260,7 +2370,8 @@ Other Style Guides (from Airbnb) dragon.setAge(25); ``` - - [23.3](#23.3) If the property is a `boolean`, use `isVal()` or `hasVal()`. + + - [23.3](#accessors--boolean-prefix) If the property/method is a `boolean`, use `isVal()` or `hasVal()`. ```javascript // bad @@ -2274,7 +2385,8 @@ Other Style Guides (from Airbnb) } ``` - - [23.4](#23.4) It's okay to create get() and set() functions, but be consistent. + + - [23.4](#accessors--consistent) It's okay to create get() and set() functions, but be consistent. ```javascript class Jedi { @@ -2298,7 +2410,8 @@ Other Style Guides (from Airbnb) ## Events - - [24.1](#24.1) When attaching data payloads to events (whether DOM events or something more proprietary like Backbone events), pass a hash instead of a raw value. This allows a subsequent contributor to add more data to the event payload without finding and updating every handler for the event. For example, instead of: + + - [24.1](#events--hash) When attaching data payloads to events (whether DOM events or something more proprietary like Backbone events), pass a hash instead of a raw value. This allows a subsequent contributor to add more data to the event payload without finding and updating every handler for the event. For example, instead of: ```javascript // bad @@ -2329,7 +2442,8 @@ Other Style Guides (from Airbnb) ## jQuery - - [25.1](#25.1) Prefix jQuery object variables with a `$`. jscs: [`requireDollarBeforejQueryAssignment`](http://jscs.info/rule/requireDollarBeforejQueryAssignment) + + - [25.1](#jquery--dollar-prefix) Prefix jQuery object variables with a `$`. jscs: [`requireDollarBeforejQueryAssignment`](http://jscs.info/rule/requireDollarBeforejQueryAssignment) ```javascript // bad @@ -2342,7 +2456,8 @@ Other Style Guides (from Airbnb) const $sidebarBtn = $('.sidebar-btn'); ``` - - [25.2](#25.2) Cache jQuery lookups. + + - [25.2](#jquery--cache) Cache jQuery lookups. ```javascript // bad @@ -2369,8 +2484,11 @@ Other Style Guides (from Airbnb) } ``` - - [25.3](#25.3) For DOM queries use Cascading `$('.sidebar ul')` or parent > child `$('.sidebar > ul')`. [jsPerf](http://jsperf.com/jquery-find-vs-context-sel/16) - - [25.4](#25.4) Use `find` with scoped jQuery object queries. + + - [25.3](#jquery--queries) For DOM queries use Cascading `$('.sidebar ul')` or parent > child `$('.sidebar > ul')`. [jsPerf](http://jsperf.com/jquery-find-vs-context-sel/16) + + + - [25.4](#jquery--find) Use `find` with scoped jQuery object queries. ```javascript // bad @@ -2394,13 +2512,15 @@ Other Style Guides (from Airbnb) ## ECMAScript 5 Compatibility - - [26.1](#26.1) Refer to [Kangax](https://twitter.com/kangax/)'s ES5 [compatibility table](http://kangax.github.io/es5-compat-table/). + + - [26.1](#es5-compat--kangax) Refer to [Kangax](https://twitter.com/kangax/)'s ES5 [compatibility table](http://kangax.github.io/es5-compat-table/). **[⬆ back to top](#table-of-contents)** ## ECMAScript 6 Styles - - [27.1](#27.1) This is a collection of links to the various ES6 features. + + - [27.1](#es6-styles) This is a collection of links to the various ES6 features. 1. [Arrow Functions](#arrow-functions) 1. [Classes](#constructors) @@ -2420,7 +2540,8 @@ Other Style Guides (from Airbnb) ## Testing - - [28.1](#28.1) **Yup.** + + - [28.1](#esting--yup) **Yup.** ```javascript function foo() { @@ -2428,7 +2549,8 @@ Other Style Guides (from Airbnb) } ``` - - [28.2](#28.2) **No, but seriously**: + + - [28.2](#testing--for-real) **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. diff --git a/react/README.md b/react/README.md index dbe8d1913e..cc248d33e2 100644 --- a/react/README.md +++ b/react/README.md @@ -32,7 +32,7 @@ ## Class vs `React.createClass` vs stateless - - If you have internal state and/or refs, prefer `class extends React.Component` over `React.createClass` unless you have a very good reason to use mixins. eslint: [`react/prefer-es6-class`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/prefer-es6-class.md) + - If you have internal state and/or refs, prefer `class extends React.Component` over `React.createClass` unless you have a very good reason to use mixins. eslint: [`react/prefer-es6-class`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/prefer-es6-class.md) [`react/prefer-stateless-function`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/prefer-stateless-function.md) ```javascript // bad From 52daf725a853613759334913a376370c0f7ad96f Mon Sep 17 00:00:00 2001 From: Nick Hwang Date: Sun, 27 Mar 2016 16:48:01 -0400 Subject: [PATCH 51/54] Update with airbnb/javascript@6.2.0 --- README.md | 4 +++- es5/README.md | 1 + package.json | 2 +- packages/eslint-config-hubspot/CHANGELOG.md | 7 +++++++ packages/eslint-config-hubspot/package.json | 12 ++++++------ packages/eslint-config-hubspot/rules/es6.js | 4 +++- packages/eslint-config-hubspot/rules/react.js | 4 ++-- react/README.md | 17 +++++++++++++++++ 8 files changed, 40 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 5a5b143012..7de195c0a2 100644 --- a/README.md +++ b/README.md @@ -503,7 +503,7 @@ Other Style Guides (from Airbnb) } // the caller selects only the data they need - const { left, right } = processInput(input); + const { left, top } = processInput(input); ``` @@ -2741,6 +2741,7 @@ Other Style Guides (from Airbnb) - **Adult Swim**: [adult-swim/javascript](https://github.com/adult-swim/javascript) - **Airbnb**: [airbnb/javascript](https://github.com/airbnb/javascript) - **Apartmint**: [apartmint/javascript](https://github.com/apartmint/javascript) + - **Ascribe**: [ascribe/javascript](https://github.com/ascribe/javascript) - **Avalara**: [avalara/javascript](https://github.com/avalara/javascript) - **Avant**: [avantcredit/javascript](https://github.com/avantcredit/javascript) - **Billabong**: [billabong/javascript](https://github.com/billabong/javascript) @@ -2792,6 +2793,7 @@ Other Style Guides (from Airbnb) - **Shutterfly**: [shutterfly/javascript](https://github.com/shutterfly/javascript) - **Springload**: [springload/javascript](https://github.com/springload/javascript) - **StudentSphere**: [studentsphere/javascript](https://github.com/studentsphere/guide-javascript) + - **SysGarage**: [sysgarage/javascript-style-guide](https://github.com/sysgarage/javascript-style-guide) - **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/es5/README.md b/es5/README.md index f95f25d6de..48853d610c 100644 --- a/es5/README.md +++ b/es5/README.md @@ -1674,6 +1674,7 @@ - **Shutterfly**: [shutterfly/javascript](https://github.com/shutterfly/javascript) - **StudentSphere**: [studentsphere/javascript](https://github.com/studentsphere/javascript) - **Super**: [SuperJobs/javascript](https://github.com/SuperJobs/javascript) + - **SysGarage**: [sysgarage/javascript-style-guide](https://github.com/sysgarage/javascript-style-guide) - **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/package.json b/package.json index f16c153d5a..a31eb252e8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hubspot-style", - "version": "6.1.0", + "version": "6.2.0", "description": "HubSpot's version of a mostly reasonable approach to JavaScript", "scripts": { "difftool": "./bin/difftool", diff --git a/packages/eslint-config-hubspot/CHANGELOG.md b/packages/eslint-config-hubspot/CHANGELOG.md index ab0ec2d194..0bbb7215a5 100644 --- a/packages/eslint-config-hubspot/CHANGELOG.md +++ b/packages/eslint-config-hubspot/CHANGELOG.md @@ -1,3 +1,10 @@ +6.2.0 / 2016-03-22 +================== +- [new] Allow arrow functions in JSX props +- [fix] re-enable `no-confusing-arrow` rule, with `allowParens` option enabled ([#752](https://github.com/airbnb/javascript/issues/752), [#791](https://github.com/airbnb/javascript/issues/791)) +- [dev deps] update `tape`, `eslint`, `eslint-plugin-react` +- [peer deps] update `eslint`, `eslint-plugin-react` + 6.1.0 / 2016-02-22 ================== - [new] enable [`react/prefer-stateless-function`][react/prefer-stateless-function] diff --git a/packages/eslint-config-hubspot/package.json b/packages/eslint-config-hubspot/package.json index eea409bae6..94357afe52 100644 --- a/packages/eslint-config-hubspot/package.json +++ b/packages/eslint-config-hubspot/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-hubspot", - "version": "6.1.0", + "version": "6.2.0", "description": "HubSpot's ESLint config, following our styleguide", "main": "index.js", "scripts": { @@ -32,21 +32,21 @@ }, "homepage": "https://github.com/HubSpot/javascript", "devDependencies": { - "babel-eslint": "^6.0.0-beta.5", + "babel-eslint": "^6.0.0", "babel-plugin-transform-export-extensions": "^6.5.0", "babel-plugin-transform-strict-mode": "^6.6.5", "babel-preset-es2015": "^6.6.0", "babel-tape-runner": "^2.0.1", - "eslint": "2.2.0", + "eslint": "^2.4.0", "eslint-plugin-babel": "^3.1.0", - "eslint-plugin-react": "^4.2.0", + "eslint-plugin-react": "^4.2.3", "faucet": "^0.0.1", "parallelshell": "^2.0.0", "react": "^0.14.7", "tape": "^4.5.1" }, "peerDependencies": { - "eslint": "^2.2.0", - "eslint-plugin-react": "^4.0.0" + "eslint": "^2.4.0", + "eslint-plugin-react": "^4.2.3" } } diff --git a/packages/eslint-config-hubspot/rules/es6.js b/packages/eslint-config-hubspot/rules/es6.js index 4783db126f..296630aea8 100644 --- a/packages/eslint-config-hubspot/rules/es6.js +++ b/packages/eslint-config-hubspot/rules/es6.js @@ -31,7 +31,9 @@ module.exports = { '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': 0, + 'no-confusing-arrow': [2, { + 'allowParens': true, + }], // disallow modifying variables that are declared using const 'no-const-assign': 2, // disallow symbol constructor diff --git a/packages/eslint-config-hubspot/rules/react.js b/packages/eslint-config-hubspot/rules/react.js index a12f9003ae..4a0166e5fe 100644 --- a/packages/eslint-config-hubspot/rules/react.js +++ b/packages/eslint-config-hubspot/rules/react.js @@ -41,8 +41,8 @@ module.exports = { // 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, { - 'ignoreRefs': false, - 'allowArrowFunctions': false, + 'ignoreRefs': true, + 'allowArrowFunctions': true, 'allowBind': false, }], // Prevent duplicate props in JSX diff --git a/react/README.md b/react/README.md index cc248d33e2..d8d818b753 100644 --- a/react/README.md +++ b/react/README.md @@ -347,6 +347,23 @@ ## Methods + - Use arrow functions to close over local variables. + + ```javascript + function ItemList(props) { + return ( +
    + {props.items.map((item, index) => ( + doSomethingWith(item.name, index)} + /> + ))} +
+ ); + } + ``` + - Bind event handlers for the render method in the constructor. eslint: [`react/jsx-no-bind`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-bind.md) > Why? A bind call in the render path creates a brand new function on every single render. From c133acc2751f76d404dd04215fee33a09857262f Mon Sep 17 00:00:00 2001 From: Trevor Burnham Date: Thu, 15 Sep 2016 11:50:26 -0400 Subject: [PATCH 52/54] Remove rule about specifying defaults for non-required `propTypes` --- react/README.md | 29 ----------------------------- 1 file changed, 29 deletions(-) diff --git a/react/README.md b/react/README.md index d8d818b753..4c3f3c513e 100644 --- a/react/README.md +++ b/react/README.md @@ -261,35 +261,6 @@ }); ``` - - Always provide defaults for non-required `propTypes` - - ```javascript - // bad (missing default value for `b` and `z` props) - const Component = React.createClass({ - propTypes: { - a: React.PropTypes.any.isRequired, - b: React.PropTypes.string, - z: React.PropTypes.number - } - }); - - // good - const Component = React.createClass({ - propTypes: { - a: React.PropTypes.any.isRequired, - b: React.PropTypes.string, - z: React.PropTypes.number - }, - - getDefaultProps() { - return { - b: 'something', - z: 0 - } - } - }); - ``` - ## Parentheses - Wrap JSX tags in parentheses when they span more than one line. eslint: [`react/wrap-multilines`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/wrap-multilines.md) From 37397caebdaeff0f434907914d4b5dc0db3cebd1 Mon Sep 17 00:00:00 2001 From: Nick Hwang Date: Thu, 29 Dec 2016 11:26:57 -0500 Subject: [PATCH 53/54] Add project moved banner --- README.md | 2 ++ packages/eslint-config-hubspot/README.md | 2 ++ 2 files changed, 4 insertions(+) diff --git a/README.md b/README.md index 7de195c0a2..cd9e13bb48 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +### Project moved to [HubSpot/eslint-config](https://github.com/HubSpot/eslint-config) + # HubSpot JavaScript Style Guide() { [![npm version](https://badge.fury.io/js/hubspot-style.svg)](https://badge.fury.io/js/hubspot-style) diff --git a/packages/eslint-config-hubspot/README.md b/packages/eslint-config-hubspot/README.md index 8b51d02bed..b8d37c7551 100644 --- a/packages/eslint-config-hubspot/README.md +++ b/packages/eslint-config-hubspot/README.md @@ -1,3 +1,5 @@ +### Project moved to [HubSpot/eslint-config](https://github.com/HubSpot/eslint-config) + # eslint-config-hubspot [![npm version](https://badge.fury.io/js/eslint-config-hubspot.svg)](https://badge.fury.io/js/eslint-config-hubspot) From 4328e4b480fcce30195513d0ac4e7a6e8b199739 Mon Sep 17 00:00:00 2001 From: Jacob Hilker Date: Thu, 7 Nov 2019 14:28:31 -0500 Subject: [PATCH 54/54] Update README to include archive notice --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index cd9e13bb48..2460217ad0 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ -### Project moved to [HubSpot/eslint-config](https://github.com/HubSpot/eslint-config) +## Project moved to [HubSpot/eslint-config](https://github.com/HubSpot/eslint-config). Both repos are archived in favor of an internal version of our ESLint config + # HubSpot JavaScript Style Guide() {