├── .editorconfig ├── .gitignore ├── .npmrc ├── .travis.yml ├── LICENSE.md ├── README.md ├── css-in-javascript └── README.md ├── linters ├── .eslintrc ├── .jshintrc ├── .markdownlint.json └── SublimeLinter │ └── SublimeLinter.sublime-settings ├── package.json ├── packages ├── eslint-config-airbnb-base │ ├── .babelrc │ ├── .editorconfig │ ├── .eslintrc │ ├── .npmrc │ ├── CHANGELOG.md │ ├── README.md │ ├── index.js │ ├── legacy.js │ ├── package.json │ ├── rules │ │ ├── best-practices.js │ │ ├── errors.js │ │ ├── es6.js │ │ ├── imports.js │ │ ├── node.js │ │ ├── strict.js │ │ ├── style.js │ │ └── variables.js │ └── test │ │ ├── .eslintrc │ │ └── test-base.js └── eslint-config-airbnb │ ├── .babelrc │ ├── .editorconfig │ ├── .eslintrc │ ├── .npmrc │ ├── CHANGELOG.md │ ├── README.md │ ├── base.js │ ├── index.js │ ├── legacy.js │ ├── package.json │ ├── rules │ ├── react-a11y.js │ └── react.js │ └── test │ ├── .eslintrc │ ├── test-base.js │ └── test-react-order.js └── react └── README.md /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | charset = utf-8 7 | trim_trailing_whitespace = true 8 | insert_final_newline = true 9 | end_of_line = lf 10 | # editorconfig-tools is unable to ignore longs strings or urls 11 | max_line_length = null 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # gitignore 2 | 3 | node_modules 4 | 5 | # Only apps should have lockfiles 6 | yarn.lock 7 | package-lock.json 8 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | package-lock=false 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "8" 4 | - "7" 5 | - "6" 6 | - "5" 7 | - "4" 8 | before_install: 9 | - 'if [ "${TRAVIS_NODE_VERSION}" = "0.6" ]; then npm install -g npm@1.3 ; elif [ "${TRAVIS_NODE_VERSION}" != "0.9" ]; then case "$(npm --version)" in 1.*) npm install -g npm@1.4.28 ;; 2.*) npm install -g npm@2 ;; esac ; fi' 10 | - 'if [ "${TRAVIS_NODE_VERSION%${TRAVIS_NODE_VERSION#[0-9]}}" = "0" ] || [ "${TRAVIS_NODE_VERSION:0:4}" = "iojs" ]; then npm install -g npm@4.5 ; elif [ "${TRAVIS_NODE_VERSION}" != "0.6" ] && [ "${TRAVIS_NODE_VERSION}" != "0.9" ]; then npm install -g npm; fi' 11 | install: 12 | - 'cd "packages/${PACKAGE}"' 13 | - 'if [ "${TRAVIS_NODE_VERSION}" = "0.6" ]; then nvm install 0.8 && npm install -g npm@1.3 && npm install -g npm@1.4.28 && npm install -g npm@2 && npm install && nvm use "${TRAVIS_NODE_VERSION}"; else npm install; fi;' 14 | - 'if [ -n "${ESLINT}" ]; then npm install --no-save "eslint@${ESLINT}"; fi' 15 | script: 16 | - 'if [ -n "${PREPUBLISH-}" ]; then npm run pretravis && npm run prepublish && npm run posttravis; else npm run travis; fi' 17 | sudo: false 18 | env: 19 | matrix: 20 | - 'TEST=true ESLINT=3 PACKAGE=eslint-config-airbnb' 21 | - 'TEST=true ESLINT=4 PACKAGE=eslint-config-airbnb' 22 | - 'TEST=true ESLINT=3 PACKAGE=eslint-config-airbnb-base' 23 | - 'TEST=true ESLINT=4 PACKAGE=eslint-config-airbnb-base' 24 | matrix: 25 | fast_finish: true 26 | include: 27 | - node_js: "node" 28 | env: PREPUBLISH=true ESLINT=3 PACKAGE=eslint-config-airbnb 29 | - node_js: "node" 30 | env: PREPUBLISH=true ESLINT=4 PACKAGE=eslint-config-airbnb 31 | - node_js: "node" 32 | env: PREPUBLISH=true ESLINT=3 PACKAGE=eslint-config-airbnb-base 33 | - node_js: "node" 34 | env: PREPUBLISH=true ESLINT=4 PACKAGE=eslint-config-airbnb-base 35 | allow_failures: 36 | - node_js: "7" 37 | - node_js: "5" 38 | - env: PREPUBLISH=true ESLINT=3 PACKAGE=eslint-config-airbnb 39 | - env: PREPUBLISH=true ESLINT=4 PACKAGE=eslint-config-airbnb 40 | - env: PREPUBLISH=true ESLINT=3 PACKAGE=eslint-config-airbnb-base 41 | - env: PREPUBLISH=true ESLINT=4 PACKAGE=eslint-config-airbnb-base 42 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Airbnb 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /css-in-javascript/README.md: -------------------------------------------------------------------------------- 1 | # Airbnb CSS-in-JavaScript Style Guide 2 | 3 | *A mostly reasonable approach to CSS-in-JavaScript 4 | 5 | ## Table of Contents 6 | 7 | 1. [Naming](#naming) 8 | 1. [Ordering](#ordering) 9 | 1. [Nesting](#nesting) 10 | 1. [Inline](#inline) 11 | 1. [Themes](#themes) 12 | 13 | ## Naming 14 | 15 | - Use camelCase for object keys (i.e. "selectors"). 16 | 17 | > Why? We access these keys as properties on the `styles` object in the component, so it is most convenient to use camelCase. 18 | 19 | ```js 20 | // bad 21 | { 22 | 'bermuda-triangle': { 23 | display: 'none', 24 | }, 25 | } 26 | 27 | // good 28 | { 29 | bermudaTriangle: { 30 | display: 'none', 31 | }, 32 | } 33 | ``` 34 | 35 | - Use an underscore for modifiers to other styles. 36 | 37 | > Why? Similar to BEM, this naming convention makes it clear that the styles are intended to modify the element preceded by the underscore. Underscores do not need to be quoted, so they are preferred over other characters, such as dashes. 38 | 39 | ```js 40 | // bad 41 | { 42 | bruceBanner: { 43 | color: 'pink', 44 | transition: 'color 10s', 45 | }, 46 | 47 | bruceBannerTheHulk: { 48 | color: 'green', 49 | }, 50 | } 51 | 52 | // good 53 | { 54 | bruceBanner: { 55 | color: 'pink', 56 | transition: 'color 10s', 57 | }, 58 | 59 | bruceBanner_theHulk: { 60 | color: 'green', 61 | }, 62 | } 63 | ``` 64 | 65 | - Use `selectorName_fallback` for sets of fallback styles. 66 | 67 | > Why? Similar to modifiers, keeping the naming consistent helps reveal the relationship of these styles to the styles that override them in more adequate browsers. 68 | 69 | ```js 70 | // bad 71 | { 72 | muscles: { 73 | display: 'flex', 74 | }, 75 | 76 | muscles_sadBears: { 77 | width: '100%', 78 | }, 79 | } 80 | 81 | // good 82 | { 83 | muscles: { 84 | display: 'flex', 85 | }, 86 | 87 | muscles_fallback: { 88 | width: '100%', 89 | }, 90 | } 91 | ``` 92 | 93 | - Use a separate selector for sets of fallback styles. 94 | 95 | > Why? Keeping fallback styles contained in a separate object clarifies their purpose, which improves readability. 96 | 97 | ```js 98 | // bad 99 | { 100 | muscles: { 101 | display: 'flex', 102 | }, 103 | 104 | left: { 105 | flexGrow: 1, 106 | display: 'inline-block', 107 | }, 108 | 109 | right: { 110 | display: 'inline-block', 111 | }, 112 | } 113 | 114 | // good 115 | { 116 | muscles: { 117 | display: 'flex', 118 | }, 119 | 120 | left: { 121 | flexGrow: 1, 122 | }, 123 | 124 | left_fallback: { 125 | display: 'inline-block', 126 | }, 127 | 128 | right_fallback: { 129 | display: 'inline-block', 130 | }, 131 | } 132 | ``` 133 | 134 | - Use device-agnostic names (e.g. "small", "medium", and "large") to name media query breakpoints. 135 | 136 | > Why? Commonly used names like "phone", "tablet", and "desktop" do not match the characteristics of the devices in the real world. Using these names sets the wrong expectations. 137 | 138 | ```js 139 | // bad 140 | const breakpoints = { 141 | mobile: '@media (max-width: 639px)', 142 | tablet: '@media (max-width: 1047px)', 143 | desktop: '@media (min-width: 1048px)', 144 | }; 145 | 146 | // good 147 | const breakpoints = { 148 | small: '@media (max-width: 639px)', 149 | medium: '@media (max-width: 1047px)', 150 | large: '@media (min-width: 1048px)', 151 | }; 152 | ``` 153 | 154 | ## Ordering 155 | 156 | - Define styles after the component. 157 | 158 | > Why? We use a higher-order component to theme our styles, which is naturally used after the component definition. Passing the styles object directly to this function reduces indirection. 159 | 160 | ```jsx 161 | // bad 162 | const styles = { 163 | container: { 164 | display: 'inline-block', 165 | }, 166 | }; 167 | 168 | function MyComponent({ styles }) { 169 | return ( 170 |
171 | Never doubt that a small group of thoughtful, committed citizens can 172 | change the world. Indeed, it’s the only thing that ever has. 173 |
174 | ); 175 | } 176 | 177 | export default withStyles(() => styles)(MyComponent); 178 | 179 | // good 180 | function MyComponent({ styles }) { 181 | return ( 182 |
183 | Never doubt that a small group of thoughtful, committed citizens can 184 | change the world. Indeed, it’s the only thing that ever has. 185 |
186 | ); 187 | } 188 | 189 | export default withStyles(() => ({ 190 | container: { 191 | display: 'inline-block', 192 | }, 193 | }))(MyComponent); 194 | ``` 195 | 196 | ## Nesting 197 | 198 | - Leave a blank line between adjacent blocks at the same indentation level. 199 | 200 | > Why? The whitespace improves readability and reduces the likelihood of merge conflicts. 201 | 202 | ```js 203 | // bad 204 | { 205 | bigBang: { 206 | display: 'inline-block', 207 | '::before': { 208 | content: "''", 209 | }, 210 | }, 211 | universe: { 212 | border: 'none', 213 | }, 214 | } 215 | 216 | // good 217 | { 218 | bigBang: { 219 | display: 'inline-block', 220 | 221 | '::before': { 222 | content: "''", 223 | }, 224 | }, 225 | 226 | universe: { 227 | border: 'none', 228 | }, 229 | } 230 | ``` 231 | 232 | ## Inline 233 | 234 | - Use inline styles for styles that have a high cardinality (e.g. uses the value of a prop) and not for styles that have a low cardinality. 235 | 236 | > Why? Generating themed stylesheets can be expensive, so they are best for discrete sets of styles. 237 | 238 | ```jsx 239 | // bad 240 | export default function MyComponent({ spacing }) { 241 | return ( 242 |
243 | ); 244 | } 245 | 246 | // good 247 | function MyComponent({ styles, spacing }) { 248 | return ( 249 |
250 | ); 251 | } 252 | export default withStyles(() => ({ 253 | periodic: { 254 | display: 'table', 255 | }, 256 | }))(MyComponent); 257 | ``` 258 | 259 | ## Themes 260 | 261 | - Use an abstraction layer such as [react-with-styles](https://github.com/airbnb/react-with-styles) that enables theming. *react-with-styles gives us things like `withStyles()`, `ThemedStyleSheet`, and `css()` which are used in some of the examples in this document.* 262 | 263 | > Why? It is useful to have a set of shared variables for styling your components. Using an abstraction layer makes this more convenient. Additionally, this can help prevent your components from being tightly coupled to any particular underlying implementation, which gives you more freedom. 264 | 265 | - Define colors only in themes. 266 | 267 | ```js 268 | // bad 269 | export default withStyles(() => ({ 270 | chuckNorris: { 271 | color: '#bada55', 272 | }, 273 | }))(MyComponent); 274 | 275 | // good 276 | export default withStyles(({ color }) => ({ 277 | chuckNorris: { 278 | color: color.badass, 279 | }, 280 | }))(MyComponent); 281 | ``` 282 | 283 | - Define fonts only in themes. 284 | 285 | ```js 286 | // bad 287 | export default withStyles(() => ({ 288 | towerOfPisa: { 289 | fontStyle: 'italic', 290 | }, 291 | }))(MyComponent); 292 | 293 | // good 294 | export default withStyles(({ font }) => ({ 295 | towerOfPisa: { 296 | fontStyle: font.italic, 297 | }, 298 | }))(MyComponent); 299 | ``` 300 | 301 | - Define fonts as sets of related styles. 302 | 303 | ```js 304 | // bad 305 | export default withStyles(() => ({ 306 | towerOfPisa: { 307 | fontFamily: 'Italiana, "Times New Roman", serif', 308 | fontSize: '2em', 309 | fontStyle: 'italic', 310 | lineHeight: 1.5, 311 | }, 312 | }))(MyComponent); 313 | 314 | // good 315 | export default withStyles(({ font }) => ({ 316 | towerOfPisa: { 317 | ...font.italian, 318 | }, 319 | }))(MyComponent); 320 | ``` 321 | 322 | - Define base grid units in theme (either as a value or a function that takes a multiplier). 323 | 324 | ```js 325 | // bad 326 | export default withStyles(() => ({ 327 | rip: { 328 | bottom: '-6912px', // 6 feet 329 | }, 330 | }))(MyComponent); 331 | 332 | // good 333 | export default withStyles(({ units }) => ({ 334 | rip: { 335 | bottom: units(864), // 6 feet, assuming our unit is 8px 336 | }, 337 | }))(MyComponent); 338 | 339 | // good 340 | export default withStyles(({ unit }) => ({ 341 | rip: { 342 | bottom: 864 * unit, // 6 feet, assuming our unit is 8px 343 | }, 344 | }))(MyComponent); 345 | ``` 346 | 347 | - Define media queries only in themes. 348 | 349 | ```js 350 | // bad 351 | export default withStyles(() => ({ 352 | container: { 353 | width: '100%', 354 | 355 | '@media (max-width: 1047px)': { 356 | width: '50%', 357 | }, 358 | }, 359 | }))(MyComponent); 360 | 361 | // good 362 | export default withStyles(({ breakpoint }) => ({ 363 | container: { 364 | width: '100%', 365 | 366 | [breakpoint.medium]: { 367 | width: '50%', 368 | }, 369 | }, 370 | }))(MyComponent); 371 | ``` 372 | 373 | - Define tricky fallback properties in themes. 374 | 375 | > Why? Many CSS-in-JavaScript implementations merge style objects together which makes specifying fallbacks for the same property (e.g. `display`) a little tricky. To keep the approach unified, put these fallbacks in the theme. 376 | 377 | ```js 378 | // bad 379 | export default withStyles(() => ({ 380 | .muscles { 381 | display: 'flex', 382 | }, 383 | 384 | .muscles_fallback { 385 | 'display ': 'table', 386 | }, 387 | }))(MyComponent); 388 | 389 | // good 390 | export default withStyles(({ fallbacks }) => ({ 391 | .muscles { 392 | display: 'flex', 393 | }, 394 | 395 | .muscles_fallback { 396 | [fallbacks.display]: 'table', 397 | }, 398 | }))(MyComponent); 399 | 400 | // good 401 | export default withStyles(({ fallback }) => ({ 402 | .muscles { 403 | display: 'flex', 404 | }, 405 | 406 | .muscles_fallback { 407 | [fallback('display')]: 'table', 408 | }, 409 | }))(MyComponent); 410 | ``` 411 | 412 | - Create as few custom themes as possible. Many applications may only have one theme. 413 | 414 | - Namespace custom theme settings under a nested object with a unique and descriptive key. 415 | 416 | ```js 417 | // bad 418 | ThemedStyleSheet.registerTheme('mySection', { 419 | mySectionPrimaryColor: 'green', 420 | }); 421 | 422 | // good 423 | ThemedStyleSheet.registerTheme('mySection', { 424 | mySection: { 425 | primaryColor: 'green', 426 | }, 427 | }); 428 | ``` 429 | 430 | --- 431 | 432 | CSS puns adapted from [Saijo George](http://saijogeorge.com/css-puns/). 433 | -------------------------------------------------------------------------------- /linters/.eslintrc: -------------------------------------------------------------------------------- 1 | // Use this file as a starting point for your project's .eslintrc. 2 | // Copy this file, and add rule overrides as needed. 3 | { 4 | "extends": "airbnb" 5 | } 6 | -------------------------------------------------------------------------------- /linters/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | /* 3 | * ENVIRONMENTS 4 | * ================= 5 | */ 6 | 7 | // Define globals exposed by modern browsers. 8 | "browser": true, 9 | 10 | // Define globals exposed by jQuery. 11 | "jquery": true, 12 | 13 | // Define globals exposed by Node.js. 14 | "node": true, 15 | 16 | // Allow ES6. 17 | "esversion": 6, 18 | 19 | /* 20 | * ENFORCING OPTIONS 21 | * ================= 22 | */ 23 | 24 | // Force all variable names to use either camelCase style or UPPER_CASE 25 | // with underscores. 26 | "camelcase": true, 27 | 28 | // Prohibit use of == and != in favor of === and !==. 29 | "eqeqeq": true, 30 | 31 | // Enforce tab width of 2 spaces. 32 | "indent": 2, 33 | 34 | // Prohibit use of a variable before it is defined. 35 | "latedef": true, 36 | 37 | // Enforce line length to 100 characters 38 | "maxlen": 100, 39 | 40 | // Require capitalized names for constructor functions. 41 | "newcap": true, 42 | 43 | // Enforce use of single quotation marks for strings. 44 | "quotmark": "single", 45 | 46 | // Enforce placing 'use strict' at the top function scope 47 | "strict": true, 48 | 49 | // Prohibit use of explicitly undeclared variables. 50 | "undef": true, 51 | 52 | // Warn when variables are defined but never used. 53 | "unused": true, 54 | 55 | /* 56 | * RELAXING OPTIONS 57 | * ================= 58 | */ 59 | 60 | // Suppress warnings about == null comparisons. 61 | "eqnull": true 62 | } 63 | -------------------------------------------------------------------------------- /linters/.markdownlint.json: -------------------------------------------------------------------------------- 1 | { 2 | "comment": "Be explicit by listing every available rule. https://github.com/DavidAnson/markdownlint/blob/master/doc/Rules.md", 3 | "comment": "Note that there will be numeric gaps, not every MD number is implemented in markdownlint.", 4 | 5 | "comment": "MD001: Header levels should only increment by one level at a time", 6 | "header-increment": true, 7 | 8 | "comment": "MD002: First header should be a top level header", 9 | "first-header-h1": true, 10 | 11 | "comment": "MD003: Header style: start with hashes", 12 | "header-style": { 13 | "style": "atx" 14 | }, 15 | 16 | "comment": "MD004: Unordered list style", 17 | "ul-style": { 18 | "style": "dash" 19 | }, 20 | 21 | "comment": "MD005: Consistent indentation for list items at the same level", 22 | "list-indent": true, 23 | 24 | "comment": "MD006: Consider starting bulleted lists at the beginning of the line", 25 | "ul-start-left": false, 26 | 27 | "comment": "MD007: Unordered list indentation: 2 spaces", 28 | "ul-indent": { 29 | "indent": 2 30 | }, 31 | 32 | "comment": "MD009: Disallow trailing spaces", 33 | "no-trailing-spaces": { 34 | "br-spaces": 0, 35 | "comment": "Empty lines inside list items should not be indented", 36 | "list_item_empty_lines": false 37 | }, 38 | 39 | "comment": "MD010: No hard tabs, not even in code blocks", 40 | "no-hard-tabs": { 41 | "code_blocks": true 42 | }, 43 | 44 | "comment": "MD011: Prevent reversed link syntax", 45 | "no-reversed-links": true, 46 | 47 | "comment": "MD012: Disallow multiple consecutive blank lines", 48 | "no-multiple-blanks": { 49 | "maximum": 1 50 | }, 51 | 52 | "comment": "MD013: Line length", 53 | "line-length": false, 54 | 55 | "comment": "MD014: Disallow dollar signs used before commands without showing output", 56 | "commands-show-output": true, 57 | 58 | "comment": "MD018: Disallow space after hash on atx style header", 59 | "no-missing-space-atx": true, 60 | 61 | "comment": "MD019: Dissalow multiple spaces after hash on atx style header", 62 | "no-multiple-space-atx": true, 63 | 64 | "comment": "MD020: No space inside hashes on closed atx style header", 65 | "no-missing-space-closed-atx": true, 66 | 67 | "comment": "MD021: Disallow multiple spaces inside hashes on closed atx style header", 68 | "no-multiple-space-closed-atx": true, 69 | 70 | "comment": "MD022: Headers should be surrounded by blank lines", 71 | "comment": "Some headers have preceeding HTML anchors. Unfortunate that we have to disable this, as it otherwise catches a real problem that trips up some Markdown renderers", 72 | "blanks-around-headers": false, 73 | 74 | "comment": "MD023: Headers must start at the beginning of the line", 75 | "header-start-left": true, 76 | 77 | "comment": "MD024: Disallow multiple headers with the same content", 78 | "no-duplicate-header": true, 79 | 80 | "comment": "MD025: Disallow multiple top level headers in the same document", 81 | "comment": "Gotta have a matching closing brace at the end", 82 | "single-h1": false, 83 | 84 | "comment": "MD026: Disallow trailing punctuation in header", 85 | "comment": "Gotta have a semicolon after the ending closing brace", 86 | "no-trailing-punctuation": { 87 | "punctuation" : ".,:!?" 88 | }, 89 | "comment": "MD027: Dissalow multiple spaces after blockquote symbol", 90 | "no-multiple-space-blockquote": true, 91 | 92 | "comment": "MD028: Blank line inside blockquote", 93 | "comment": "Some 'Why?' and 'Why not?' blocks are separated by a blank line", 94 | "no-blanks-blockquote": false, 95 | 96 | "comment": "MD029: Ordered list item prefix", 97 | "ol-prefix": { 98 | "style": "one" 99 | }, 100 | 101 | "comment": "MD030: Spaces after list markers", 102 | "list-marker-space": { 103 | "ul_single": 1, 104 | "ol_single": 1, 105 | "ul_multi": 1, 106 | "ol_multi": 1 107 | }, 108 | 109 | "comment": "MD031: Fenced code blocks should be surrounded by blank lines", 110 | "blanks-around-fences": true, 111 | 112 | "comment": "MD032: Lists should be surrounded by blank lines", 113 | "comment": "Some lists have preceeding HTML anchors. Unfortunate that we have to disable this, as it otherwise catches a real problem that trips up some Markdown renderers", 114 | "blanks-around-lists": false, 115 | 116 | "comment": "MD033: Disallow inline HTML", 117 | "comment": "HTML is needed for explicit anchors", 118 | "no-inline-html": false, 119 | 120 | "comment": "MD034: No bare URLs used", 121 | "no-bare-urls": true, 122 | 123 | "comment": "MD035: Horizontal rule style", 124 | "hr-style": { 125 | "style": "consistent" 126 | }, 127 | 128 | "comment": "MD036: Do not use emphasis instead of a header", 129 | "no-emphasis-as-header": false, 130 | 131 | "comment": "MD037: Disallow spaces inside emphasis markers", 132 | "no-space-in-emphasis": true, 133 | 134 | "comment": "MD038: Disallow spaces inside code span elements", 135 | "no-space-in-code": true, 136 | 137 | "comment": "MD039: Disallow spaces inside link text", 138 | "no-space-in-links": true, 139 | 140 | "comment": "MD040: Fenced code blocks should have a language specified", 141 | "fenced-code-language": true, 142 | 143 | "comment": "MD041: First line in file should be a top level header", 144 | "first-line-h1": true, 145 | 146 | "comment": "MD042: No empty links", 147 | "no-empty-links": true, 148 | 149 | "comment": "MD043: Required header structure", 150 | "required-headers": false, 151 | 152 | "comment": "MD044: Proper names should have the correct capitalization", 153 | "proper-names": false 154 | } 155 | -------------------------------------------------------------------------------- /linters/SublimeLinter/SublimeLinter.sublime-settings: -------------------------------------------------------------------------------- 1 | /** 2 | * Airbnb JSHint settings for use with SublimeLinter and Sublime Text 2. 3 | * 4 | * 1. Install SublimeLinter at https://github.com/SublimeLinter/SublimeLinter 5 | * 2. Open user preferences for the SublimeLinter package in Sublime Text 2 6 | * * For Mac OS X go to _Sublime Text 2_ > _Preferences_ > _Package Settings_ > _SublimeLinter_ > _Settings - User_ 7 | * 3. Paste the contents of this file into your settings file 8 | * 4. Save the settings file 9 | * 10 | * @version 0.3.0 11 | * @see https://github.com/SublimeLinter/SublimeLinter 12 | * @see http://www.jshint.com/docs/ 13 | */ 14 | { 15 | "jshint_options": 16 | { 17 | /* 18 | * ENVIRONMENTS 19 | * ================= 20 | */ 21 | 22 | // Define globals exposed by modern browsers. 23 | "browser": true, 24 | 25 | // Define globals exposed by jQuery. 26 | "jquery": true, 27 | 28 | // Define globals exposed by Node.js. 29 | "node": true, 30 | 31 | /* 32 | * ENFORCING OPTIONS 33 | * ================= 34 | */ 35 | 36 | // Force all variable names to use either camelCase style or UPPER_CASE 37 | // with underscores. 38 | "camelcase": true, 39 | 40 | // Prohibit use of == and != in favor of === and !==. 41 | "eqeqeq": true, 42 | 43 | // Suppress warnings about == null comparisons. 44 | "eqnull": true, 45 | 46 | // Enforce tab width of 2 spaces. 47 | "indent": 2, 48 | 49 | // Prohibit use of a variable before it is defined. 50 | "latedef": true, 51 | 52 | // Require capitalized names for constructor functions. 53 | "newcap": true, 54 | 55 | // Enforce use of single quotation marks for strings. 56 | "quotmark": "single", 57 | 58 | // Prohibit trailing whitespace. 59 | "trailing": true, 60 | 61 | // Prohibit use of explicitly undeclared variables. 62 | "undef": true, 63 | 64 | // Warn when variables are defined but never used. 65 | "unused": true, 66 | 67 | // Enforce line length to 80 characters 68 | "maxlen": 80, 69 | 70 | // Enforce placing 'use strict' at the top function scope 71 | "strict": true 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "airbnb-style", 3 | "version": "2.0.0", 4 | "description": "A mostly reasonable approach to JavaScript.", 5 | "scripts": { 6 | "preinstall": "npm run install:config && npm run install:config:base", 7 | "install:config": "cd packages/eslint-config-airbnb && npm prune && npm install", 8 | "install:config:base": "cd packages/eslint-config-airbnb-base && npm prune && npm install", 9 | "lint": "markdownlint --config linters/.markdownlint.json README.md */README.md", 10 | "pretest": "npm run --silent lint", 11 | "test": "npm run --silent test:config && npm run --silent test:config:base", 12 | "test:config": "cd packages/eslint-config-airbnb; npm test", 13 | "test:config:base": "cd packages/eslint-config-airbnb-base; npm test", 14 | "pretravis": "npm run --silent lint", 15 | "travis": "npm run --silent travis:config && npm run --silent travis:config:base", 16 | "travis:config": "cd packages/eslint-config-airbnb; npm run travis", 17 | "travis:config:base": "cd packages/eslint-config-airbnb-base; npm run travis" 18 | }, 19 | "repository": { 20 | "type": "git", 21 | "url": "https://github.com/airbnb/javascript.git" 22 | }, 23 | "keywords": [ 24 | "style guide", 25 | "lint", 26 | "airbnb", 27 | "es6", 28 | "es2015", 29 | "react", 30 | "jsx" 31 | ], 32 | "author": "Harrison Shoff (https://twitter.com/hshoff)", 33 | "license": "MIT", 34 | "bugs": { 35 | "url": "https://github.com/airbnb/javascript/issues" 36 | }, 37 | "homepage": "https://github.com/airbnb/javascript", 38 | "devDependencies": { 39 | "markdownlint-cli": "^0.3.1" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /packages/eslint-config-airbnb-base/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["airbnb"] 3 | } 4 | -------------------------------------------------------------------------------- /packages/eslint-config-airbnb-base/.editorconfig: -------------------------------------------------------------------------------- 1 | ../../.editorconfig -------------------------------------------------------------------------------- /packages/eslint-config-airbnb-base/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./index.js", 3 | "rules": { 4 | // disable requiring trailing commas because it might be nice to revert to 5 | // being JSON at some point, and I don't want to make big changes now. 6 | "comma-dangle": 0 7 | }, 8 | } 9 | -------------------------------------------------------------------------------- /packages/eslint-config-airbnb-base/.npmrc: -------------------------------------------------------------------------------- 1 | ../../.npmrc -------------------------------------------------------------------------------- /packages/eslint-config-airbnb-base/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 11.3.1 / 2017-07-24 2 | ================== 3 | - [fix] `legacy`: remove top-level `ecmaFeatures` 4 | 5 | 11.3.0 / 2017-07-23 6 | ================== 7 | - [deps] allow eslint v3 or v4 (#1447) 8 | - [deps] update `eslint-plugin-import` 9 | - [minor] Balanced spacing for inline block comments (#1440) 10 | - [minor] `no-return-assign`: strengthen linting against returning assignments 11 | - [patch] Allow jsx extensions for test files (#1427) 12 | - [patch] `no-restricted-globals`: add confusing globals; leave disabled for now (#1420) 13 | - [patch] Support Protractor config files in import/no-extraneous-dependencies (#1456) 14 | - [docs] Remove TODO in prefer-reflect as it's deprecated (#1452) 15 | - [docs] add yarn instructions (#1463, #1464) 16 | 17 | 11.2.0 / 2017-05-14 18 | ================== 19 | - [minor] Disallow unused global variables 20 | 21 | 11.1.3 / 2017-04-03 22 | ================== 23 | - [patch] add error messages to `no-restricted-syntax` (#1353) 24 | - [deps] update `eslint` 25 | 26 | 11.1.2 / 2017-03-25 27 | ================== 28 | - [patch] `no-param-reassign`: add ignorePropertyModificationsFor (#1325) 29 | - [deps] update `eslint` 30 | 31 | 11.1.1 / 2017-03-03 32 | ================== 33 | - [deps] update `eslint` 34 | - [patch] enable `ignoreRestSiblings` in `no-unused-vars` 35 | 36 | 11.1.0 / 2017-01-08 37 | ================== 38 | - [minor] enable `no-multi-assign` 39 | - [deps] update `eslint`, `babel-preset-airbnb` 40 | - Update a deprecated option (`eqeqeq`) (#1244) 41 | 42 | 11.0.1 / 2017-01-08 43 | ================== 44 | - [deps] update `eslint` 45 | - [docs] add note about `install-peerdeps` (#1234) 46 | - [docs] Updated instructions to support non-bash users (#1214) 47 | 48 | 11.0.0 / 2016-12-11 49 | ================== 50 | - [breaking] enable `no-await-in-loop` 51 | - [patch] disable `no-duplicate-imports` rule (#1188, #1195, #1054) 52 | - [patch] `import/no-extraneous-dependencies`: add some comments to ignore patterns 53 | - [patch] add `import/no-extraneous-dependencies` ignore patterns for test files (#1174) 54 | - [patch] `import/no-extraneous-dependencies`: added ignore patterns for config files (#1168) 55 | - [deps] update `eslint`, `eslint-plugin-import`, `tape` 56 | 57 | 10.0.1 / 2016-11-07 58 | ================== 59 | - [fix] legacy config should not require `**` 60 | 61 | 10.0.0 / 2016-11-06 62 | ================== 63 | - [breaking] prefer `**` over `Math.pow` 64 | - [breaking] `comma-dangle`: require trailing commas for functions 65 | - [breaking] enable `no-useless-return` 66 | - [breaking] tighten up `indent` 67 | - [breaking] tighten up `spaced-comment` 68 | - [breaking] enable `import/no-named-default` 69 | - [patch] loosen `max-len` with `ignoreRegExpLiterals` option 70 | - [patch] loosen `no-extraneous-dependencies` for test files (#959, #1089) 71 | - [deps] update `eslint`, `eslint-plugin-import` 72 | - [dev deps] update `eslint-find-rules` 73 | - [Tests] on `node` `v7` 74 | 75 | 9.0.0 / 2016-10-16 76 | ================== 77 | - [breaking] Add `ForOfStatement` to `no-restricted-syntax` (#1122, #1134) 78 | - [breaking] enable `import/no-webpack-loader-syntax` (#1123) 79 | - [breaking] [deps] update `eslint` to `v3.8.0` (#1132) 80 | - [breaking] [deps] update `eslint-plugin-import` to v2 (#1101) 81 | - [patch] `new-cap`: add immutable.js exceptions 82 | - [docs] ensure latest version of config is installed 83 | - [dev deps] update `babel-preset-airbnb`, `eslint`, `eslint-find-rules`, `tape`, `safe-publish-latest` 84 | 85 | 8.0.0 / 2016-09-24 86 | ================== 87 | - [breaking] enable rules: `no-restricted-properties`, `prefer-numeric-literals`, `lines-around-directive`, `import/extensions`, `import/no-absolute-path`, `import/no-dynamic-require` 88 | 89 | 7.2.0 / 2016-09-23 90 | ================== 91 | - [new] set `ecmaVersion` to 2017; enable object rest/spread; update `babel-preset-airbnb` 92 | - [patch] fix category of `no-restricted-properties` 93 | - [deps] update `eslint`, `eslint-plugin-import`, `eslint-find-rules`, `safe-publish-latest` 94 | 95 | 7.1.0 / 2016-09-11 96 | ================== 97 | - [minor] enable `arrow-parens` rule 98 | 99 | 7.0.1 / 2016-09-10 100 | ================== 101 | - [patch] loosen `max-len` by ignoring strings 102 | - [deps] update to `eslint` `v3.5.0` 103 | 104 | 7.0.0 / 2016-09-06 105 | ================== 106 | - [breaking] Add no-plusplus in style.js and added explanation in README (#1012) 107 | 108 | 6.0.0 / 2016-09-06 109 | ================== 110 | - [breaking] `valid-typeof`: enable `requireStringLiterals` option 111 | - [breaking] enable `class-methods-use-this` 112 | - [breaking] enable `symbol-description` 113 | - [breaking] enable `no-bitwise` 114 | - [breaking] enable `no-tabs` 115 | - [breaking] enable `func-call-spacing` 116 | - [breaking] enable `no-template-curly-in-string` 117 | - [patch] remove redundant `DebuggerStatement` from `no-restricted-syntax` (#1031) 118 | - [deps] update `eslint`, `eslint-find-rules`, `eslint-plugin-import` 119 | - Update `ecmaVersion` to `2016` 120 | 121 | 5.0.3 / 2016-08-21 122 | ================== 123 | - [fix] correct `import/extensions` list (#1013) 124 | - [refactor] Changed ESLint rule configs to use 'off', 'warn', and 'error' instead of numbers for better readability (#946) 125 | - [deps] update `eslint`, `eslint-plugin-react` 126 | 127 | 5.0.2 / 2016-08-12 128 | ================== 129 | - [deps] update `eslint`, `eslint-find-rules`, `eslint-plugin-import` 130 | - [tests] add `safe-publish-latest` to `prepublish` 131 | 132 | 5.0.1 / 2016-07-29 133 | ================== 134 | - [patch] `no-unused-expressions`: flesh out options 135 | - [deps] update `eslint` to `v3.2`, `eslint-plugin-import` to `v1.12` 136 | - [tests] improve prepublish script 137 | 138 | 5.0.0 / 2016-07-24 139 | ================== 140 | - [breaking] enable `import/newline-after-import` 141 | - [breaking] enable overlooked rules: `linebreak-style`, `new-parens`, `no-continue`, `no-lonely-if`, `operator-assignment`, `space-unary-ops`, `dot-location`, `no-extra-boolean-cast`, `no-this-before-super`, `require-yield`, `no-path-concat`, `no-label-var`, `no-void`, `constructor-super`, `prefer-spread`, `no-new-require`, `no-undef-init`, `no-unexpected-multiline` 142 | - [deps] update `eslint`, `eslint-find-rules`, `eslint-plugin-import`, `babel-tape-runner`; add `babel-preset-airbnb` 143 | - [patch] flesh out defaults: `jsx-quotes` 144 | - [docs] update the peer dep install command to dynamically look up the right version numbers when installing peer deps 145 | - [tests] fix prepublish scripts 146 | 147 | 4.0.2 / 2016-07-14 148 | ================== 149 | - [fix] repair accidental comma-dangle change 150 | 151 | 4.0.1 / 2016-07-14 (unpublished) 152 | ================== 153 | - [fix] Prevent trailing commas in the legacy config (#950) 154 | - [deps] update `eslint-plugin-import` 155 | 156 | 4.0.0 / 2016-07-02 157 | ================== 158 | - [breaking] [deps] update `eslint` to v3; drop support for < node 4 159 | - [breaking] enable `rest-spread-spacing` rule 160 | - [breaking] enable `no-mixed-operators` rule 161 | - [breaking] enable `import` rules: `no-named-as-default`, `no-named-as-default-member`, `no-extraneous-dependencies` 162 | - [breaking] enable `object-property-newline` rule 163 | - [breaking] enable `no-prototype-builtins` rule 164 | - [breaking] enable `no-useless-rename` rule 165 | - [breaking] enable `unicode-bom` rule 166 | - [breaking] Enforce proper generator star spacing (#887) 167 | - [breaking] Enable imports/imports-first rule (#882) 168 | - [breaking] re-order rules; put import rules in separate file (#881) 169 | - [patch] `newline-per-chained-call`: bump the limit to 4 170 | - [patch] `object-shorthand`: do not warn when the concise form would have a string literal as a name 171 | - [patch] Loosen `prefer-const` to not warn when the variable is “read” before being assigned to 172 | - [refactor] fix quoting of rule properties (#885) 173 | - [refactor] `quotes`: Use object option form rather than deprecated string form. 174 | - [deps] update `eslint`, `eslint-plugin-import`, `eslint-find-rules`, `tape` 175 | - [tests] Only run `eslint-find-rules` on prepublish, not in tests 176 | 177 | 3.0.1 / 2016-05-08 178 | ================== 179 | - [patch] re-disable `no-extra-parens` (#869, #867) 180 | 181 | 3.0.0 / 2016-05-07 182 | ================== 183 | - [breaking] enable `import/no-mutable-exports` 184 | - [breaking] enable `no-class-assign` rule, to pair with `no-func-assign` 185 | - [breaking] widen `no-extra-parens` to include everything, except `nestedBinaryExpressions` 186 | - [breaking] Re-enabling `newline-per-chained-call` (#748) 187 | - [minor] enable `import/no-amd` 188 | - [patch] enable `import/no-duplicates` 189 | - [deps] update `eslint`, `eslint-plugin-import`, `eslint-find-rules` 190 | 191 | 2.0.0 / 2016-04-29 192 | ================== 193 | - [breaking] enable `no-unsafe-finally` rule 194 | - [semver-minor] enable `no-useless-computed-key` rule 195 | - [deps] update `eslint`, `eslint-plugin-import` 196 | 197 | 1.0.4 / 2016-04-26 198 | ================== 199 | - [deps] update `eslint-find-rules`, `eslint-plugin-import` 200 | 201 | 1.0.3 / 2016-04-21 202 | ================== 203 | - [patch: loosen rules] Allow empty class/object methods 204 | 205 | 1.0.2 / 2016-04-20 206 | ================== 207 | - [patch: loosen rules] Allow `break` (#840) 208 | 209 | 1.0.1 / 2016-04-19 210 | ================== 211 | - [patch: loosen rules] Allow `== null` (#542) 212 | 213 | 1.0.0 / 2016-04-19 214 | ================== 215 | - Initial commmit; moved content over from `eslint-config-airbnb` package. 216 | -------------------------------------------------------------------------------- /packages/eslint-config-airbnb-base/README.md: -------------------------------------------------------------------------------- 1 | # eslint-config-airbnb-base 2 | 3 | [![npm version](https://badge.fury.io/js/eslint-config-airbnb-base.svg)](http://badge.fury.io/js/eslint-config-airbnb-base) 4 | 5 | This package provides Airbnb's base JS .eslintrc (without React plugins) as an extensible shared config. 6 | 7 | ## Usage 8 | 9 | We export two ESLint configurations for your usage. 10 | 11 | ### eslint-config-airbnb-base 12 | 13 | Our default export contains all of our ESLint rules, including ECMAScript 6+. It requires `eslint` and `eslint-plugin-import`. 14 | 15 | If you use yarn, run `yarn add --dev eslint-config-airbnb-base eslint-plugin-import`, or see below for npm instructions. 16 | 17 | 1. Install the correct versions of each package, which are listed by the command: 18 | 19 | ```sh 20 | npm info "eslint-config-airbnb-base@latest" peerDependencies 21 | ``` 22 | 23 | Linux/OSX users can run 24 | ```sh 25 | ( 26 | export PKG=eslint-config-airbnb-base; 27 | npm info "$PKG@latest" peerDependencies --json | command sed 's/[\{\},]//g ; s/: /@/g' | xargs npm install --save-dev "$PKG@latest" 28 | ) 29 | ``` 30 | 31 | Which produces and runs a command like: 32 | 33 | ```sh 34 | npm install --save-dev eslint-config-airbnb-base eslint@^#.#.# eslint-plugin-import@^#.#.# 35 | ``` 36 | 37 | Windows users can either install all the peer dependencies manually, or use the [install-peerdeps](https://github.com/nathanhleung/install-peerdeps) cli tool. 38 | 39 | ```sh 40 | npm install -g install-peerdeps 41 | install-peerdeps --dev eslint-config-airbnb-base 42 | ``` 43 | 44 | The cli will produce and run a command like: 45 | 46 | ```sh 47 | npm install --save-dev eslint-config-airbnb-base eslint@^#.#.# eslint-plugin-import@^#.#.# 48 | ``` 49 | 50 | 2. Add `"extends": "airbnb-base"` to your .eslintrc. 51 | 52 | ### eslint-config-airbnb-base/legacy 53 | 54 | Lints ES5 and below. Requires `eslint` and `eslint-plugin-import`. 55 | 56 | 1. Install the correct versions of each package, which are listed by the command: 57 | 58 | ```sh 59 | npm info "eslint-config-airbnb-base@latest" peerDependencies 60 | ``` 61 | 62 | Linux/OSX users can run 63 | ```sh 64 | ( 65 | export PKG=eslint-config-airbnb-base; 66 | npm info "$PKG" peerDependencies --json | command sed 's/[\{\},]//g ; s/: /@/g' | xargs npm install --save-dev "$PKG" 67 | ) 68 | ``` 69 | 70 | Which produces and runs a command like: 71 | 72 | ```sh 73 | npm install --save-dev eslint-config-airbnb-base eslint@^3.0.1 eslint-plugin-import@^1.10.3 74 | ``` 75 | 76 | 2. Add `"extends": "airbnb-base/legacy"` to your .eslintrc 77 | 78 | See [Airbnb's overarching ESLint config](https://npmjs.com/eslint-config-airbnb), [Airbnb's Javascript styleguide](https://github.com/airbnb/javascript), and the [ESlint config docs](http://eslint.org/docs/user-guide/configuring#extending-configuration-files) for more information. 79 | 80 | ## Improving this config 81 | 82 | Consider adding test cases if you're making complicated rules changes, like anything involving regexes. Perhaps in a distant future, we could use literate programming to structure our README as test cases for our .eslintrc? 83 | 84 | You can run tests with `npm test`. 85 | 86 | You can make sure this module lints with itself using `npm run lint`. 87 | -------------------------------------------------------------------------------- /packages/eslint-config-airbnb-base/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: [ 3 | './rules/best-practices', 4 | './rules/errors', 5 | './rules/node', 6 | './rules/style', 7 | './rules/variables', 8 | './rules/es6', 9 | './rules/imports', 10 | ].map(require.resolve), 11 | parserOptions: { 12 | ecmaVersion: 2017, 13 | sourceType: 'module', 14 | ecmaFeatures: { 15 | experimentalObjectRestSpread: true, 16 | }, 17 | }, 18 | rules: { 19 | strict: 'error', 20 | }, 21 | }; 22 | -------------------------------------------------------------------------------- /packages/eslint-config-airbnb-base/legacy.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: [ 3 | './rules/best-practices', 4 | './rules/errors', 5 | './rules/node', 6 | './rules/style', 7 | './rules/variables' 8 | ].map(require.resolve), 9 | env: { 10 | browser: true, 11 | node: true, 12 | amd: false, 13 | mocha: false, 14 | jasmine: false 15 | }, 16 | rules: { 17 | 'comma-dangle': ['error', 'never'], 18 | 'prefer-numeric-literals': 'off', 19 | 'no-restricted-properties': ['error', { 20 | object: 'arguments', 21 | property: 'callee', 22 | message: 'arguments.callee is deprecated', 23 | }, { 24 | property: '__defineGetter__', 25 | message: 'Please use Object.defineProperty instead.', 26 | }, { 27 | property: '__defineSetter__', 28 | message: 'Please use Object.defineProperty instead.', 29 | }], 30 | } 31 | }; 32 | -------------------------------------------------------------------------------- /packages/eslint-config-airbnb-base/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "eslint-config-airbnb-base", 3 | "version": "11.3.1", 4 | "description": "Airbnb's base JS ESLint config, following our styleguide", 5 | "main": "index.js", 6 | "scripts": { 7 | "prelint": "editorconfig-tools check * rules/* test/*", 8 | "lint": "eslint .", 9 | "tests-only": "babel-tape-runner ./test/test-*.js", 10 | "prepublish": "(in-install || eslint-find-rules --unused) && (not-in-publish || npm test) && safe-publish-latest", 11 | "pretest": "npm run --silent lint", 12 | "test": "npm run --silent tests-only", 13 | "pretravis": ":", 14 | "travis": "npm run --silent test", 15 | "posttravis": ":" 16 | }, 17 | "repository": { 18 | "type": "git", 19 | "url": "https://github.com/airbnb/javascript" 20 | }, 21 | "keywords": [ 22 | "eslint", 23 | "eslintconfig", 24 | "config", 25 | "airbnb", 26 | "javascript", 27 | "styleguide" 28 | ], 29 | "author": "Jake Teton-Landis (https://twitter.com/@jitl)", 30 | "contributors": [ 31 | { 32 | "name": "Jake Teton-Landis", 33 | "url": "https://twitter.com/jitl" 34 | }, 35 | { 36 | "name": "Jordan Harband", 37 | "email": "ljharb@gmail.com", 38 | "url": "http://ljharb.codes" 39 | }, 40 | { 41 | "name": "Harrison Shoff", 42 | "url": "https://twitter.com/hshoff" 43 | } 44 | ], 45 | "license": "MIT", 46 | "bugs": { 47 | "url": "https://github.com/airbnb/javascript/issues" 48 | }, 49 | "homepage": "https://github.com/airbnb/javascript", 50 | "devDependencies": { 51 | "babel-preset-airbnb": "^2.4.0", 52 | "babel-tape-runner": "^2.0.1", 53 | "editorconfig-tools": "^0.1.1", 54 | "eslint": "^4.3.0", 55 | "eslint-find-rules": "^3.1.1", 56 | "eslint-plugin-import": "^2.7.0", 57 | "in-publish": "^2.0.0", 58 | "safe-publish-latest": "^1.1.1", 59 | "tape": "^4.7.0" 60 | }, 61 | "peerDependencies": { 62 | "eslint": "^3.19.0 || ^4.3.0", 63 | "eslint-plugin-import": "^2.7.0" 64 | }, 65 | "engines": { 66 | "node": ">= 4" 67 | }, 68 | "dependencies": { 69 | "eslint-restricted-globals": "^0.1.1" 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /packages/eslint-config-airbnb-base/rules/best-practices.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | rules: { 3 | // enforces getter/setter pairs in objects 4 | 'accessor-pairs': 'off', 5 | 6 | // enforces return statements in callbacks of array's methods 7 | // http://eslint.org/docs/rules/array-callback-return 8 | 'array-callback-return': 'error', 9 | 10 | // treat var statements as if they were block scoped 11 | 'block-scoped-var': 'error', 12 | 13 | // specify the maximum cyclomatic complexity allowed in a program 14 | complexity: ['off', 11], 15 | 16 | // enforce that class methods use "this" 17 | // http://eslint.org/docs/rules/class-methods-use-this 18 | 'class-methods-use-this': ['error', { 19 | exceptMethods: [], 20 | }], 21 | 22 | // require return statements to either always or never specify values 23 | 'consistent-return': 'error', 24 | 25 | // specify curly brace conventions for all control statements 26 | curly: ['error', 'multi-line'], 27 | 28 | // require default case in switch statements 29 | 'default-case': ['error', { commentPattern: '^no default$' }], 30 | 31 | // encourages use of dot notation whenever possible 32 | 'dot-notation': ['error', { allowKeywords: true }], 33 | 34 | // enforces consistent newlines before or after dots 35 | // http://eslint.org/docs/rules/dot-location 36 | 'dot-location': ['error', 'property'], 37 | 38 | // require the use of === and !== 39 | // http://eslint.org/docs/rules/eqeqeq 40 | eqeqeq: ['error', 'always', { null: 'ignore' }], 41 | 42 | // make sure for-in loops have an if statement 43 | 'guard-for-in': 'error', 44 | 45 | // disallow the use of alert, confirm, and prompt 46 | 'no-alert': 'warn', 47 | 48 | // disallow use of arguments.caller or arguments.callee 49 | 'no-caller': 'error', 50 | 51 | // disallow lexical declarations in case/default clauses 52 | // http://eslint.org/docs/rules/no-case-declarations.html 53 | 'no-case-declarations': 'error', 54 | 55 | // disallow division operators explicitly at beginning of regular expression 56 | // http://eslint.org/docs/rules/no-div-regex 57 | 'no-div-regex': 'off', 58 | 59 | // disallow else after a return in an if 60 | 'no-else-return': 'error', 61 | 62 | // disallow empty functions, except for standalone funcs/arrows 63 | // http://eslint.org/docs/rules/no-empty-function 64 | 'no-empty-function': ['error', { 65 | allow: [ 66 | 'arrowFunctions', 67 | 'functions', 68 | 'methods', 69 | ] 70 | }], 71 | 72 | // disallow empty destructuring patterns 73 | // http://eslint.org/docs/rules/no-empty-pattern 74 | 'no-empty-pattern': 'error', 75 | 76 | // disallow comparisons to null without a type-checking operator 77 | 'no-eq-null': 'off', 78 | 79 | // disallow use of eval() 80 | 'no-eval': 'error', 81 | 82 | // disallow adding to native types 83 | 'no-extend-native': 'error', 84 | 85 | // disallow unnecessary function binding 86 | 'no-extra-bind': 'error', 87 | 88 | // disallow Unnecessary Labels 89 | // http://eslint.org/docs/rules/no-extra-label 90 | 'no-extra-label': 'error', 91 | 92 | // disallow fallthrough of case statements 93 | 'no-fallthrough': 'error', 94 | 95 | // disallow the use of leading or trailing decimal points in numeric literals 96 | 'no-floating-decimal': 'error', 97 | 98 | // disallow reassignments of native objects or read-only globals 99 | // http://eslint.org/docs/rules/no-global-assign 100 | 'no-global-assign': ['error', { exceptions: [] }], 101 | // deprecated in favor of no-global-assign 102 | 'no-native-reassign': 'off', 103 | 104 | // disallow implicit type conversions 105 | // http://eslint.org/docs/rules/no-implicit-coercion 106 | 'no-implicit-coercion': ['off', { 107 | boolean: false, 108 | number: true, 109 | string: true, 110 | allow: [], 111 | }], 112 | 113 | // disallow var and named functions in global scope 114 | // http://eslint.org/docs/rules/no-implicit-globals 115 | 'no-implicit-globals': 'off', 116 | 117 | // disallow use of eval()-like methods 118 | 'no-implied-eval': 'error', 119 | 120 | // disallow this keywords outside of classes or class-like objects 121 | 'no-invalid-this': 'off', 122 | 123 | // disallow usage of __iterator__ property 124 | 'no-iterator': 'error', 125 | 126 | // disallow use of labels for anything other then loops and switches 127 | 'no-labels': ['error', { allowLoop: false, allowSwitch: false }], 128 | 129 | // disallow unnecessary nested blocks 130 | 'no-lone-blocks': 'error', 131 | 132 | // disallow creation of functions within loops 133 | 'no-loop-func': 'error', 134 | 135 | // disallow magic numbers 136 | // http://eslint.org/docs/rules/no-magic-numbers 137 | 'no-magic-numbers': ['off', { 138 | ignore: [], 139 | ignoreArrayIndexes: true, 140 | enforceConst: true, 141 | detectObjects: false, 142 | }], 143 | 144 | // disallow use of multiple spaces 145 | 'no-multi-spaces': ['error', { 146 | // ignoreEOLComments: false, // TODO: uncomment once v3 is dropped 147 | }], 148 | 149 | // disallow use of multiline strings 150 | 'no-multi-str': 'error', 151 | 152 | // disallow use of new operator when not part of the assignment or comparison 153 | 'no-new': 'error', 154 | 155 | // disallow use of new operator for Function object 156 | 'no-new-func': 'error', 157 | 158 | // disallows creating new instances of String, Number, and Boolean 159 | 'no-new-wrappers': 'error', 160 | 161 | // disallow use of (old style) octal literals 162 | 'no-octal': 'error', 163 | 164 | // disallow use of octal escape sequences in string literals, such as 165 | // var foo = 'Copyright \251'; 166 | 'no-octal-escape': 'error', 167 | 168 | // disallow reassignment of function parameters 169 | // disallow parameter object manipulation except for specific exclusions 170 | // rule: http://eslint.org/docs/rules/no-param-reassign.html 171 | 'no-param-reassign': ['error', { 172 | props: true, 173 | ignorePropertyModificationsFor: [ 174 | 'acc', // for reduce accumulators 175 | 'e', // for e.returnvalue 176 | 'ctx', // for Koa routing 177 | 'req', // for Express requests 178 | 'request', // for Express requests 179 | 'res', // for Express responses 180 | 'response', // for Express responses 181 | '$scope', // for Angular 1 scopes 182 | ] 183 | }], 184 | 185 | // disallow usage of __proto__ property 186 | 'no-proto': 'error', 187 | 188 | // disallow declaring the same variable more then once 189 | 'no-redeclare': 'error', 190 | 191 | // disallow certain object properties 192 | // http://eslint.org/docs/rules/no-restricted-properties 193 | 'no-restricted-properties': ['error', { 194 | object: 'arguments', 195 | property: 'callee', 196 | message: 'arguments.callee is deprecated', 197 | }, { 198 | property: '__defineGetter__', 199 | message: 'Please use Object.defineProperty instead.', 200 | }, { 201 | property: '__defineSetter__', 202 | message: 'Please use Object.defineProperty instead.', 203 | }, { 204 | object: 'Math', 205 | property: 'pow', 206 | message: 'Use the exponentiation operator (**) instead.', 207 | }], 208 | 209 | // disallow use of assignment in return statement 210 | 'no-return-assign': ['error', 'always'], 211 | 212 | // disallow redundant `return await` 213 | 'no-return-await': 'error', 214 | 215 | // disallow use of `javascript:` urls. 216 | 'no-script-url': 'error', 217 | 218 | // disallow self assignment 219 | // http://eslint.org/docs/rules/no-self-assign 220 | 'no-self-assign': 'error', 221 | 222 | // disallow comparisons where both sides are exactly the same 223 | 'no-self-compare': 'error', 224 | 225 | // disallow use of comma operator 226 | 'no-sequences': 'error', 227 | 228 | // restrict what can be thrown as an exception 229 | 'no-throw-literal': 'error', 230 | 231 | // disallow unmodified conditions of loops 232 | // http://eslint.org/docs/rules/no-unmodified-loop-condition 233 | 'no-unmodified-loop-condition': 'off', 234 | 235 | // disallow usage of expressions in statement position 236 | 'no-unused-expressions': ['error', { 237 | allowShortCircuit: false, 238 | allowTernary: false, 239 | allowTaggedTemplates: false, 240 | }], 241 | 242 | // disallow unused labels 243 | // http://eslint.org/docs/rules/no-unused-labels 244 | 'no-unused-labels': 'error', 245 | 246 | // disallow unnecessary .call() and .apply() 247 | 'no-useless-call': 'off', 248 | 249 | // disallow useless string concatenation 250 | // http://eslint.org/docs/rules/no-useless-concat 251 | 'no-useless-concat': 'error', 252 | 253 | // disallow unnecessary string escaping 254 | // http://eslint.org/docs/rules/no-useless-escape 255 | 'no-useless-escape': 'error', 256 | 257 | // disallow redundant return; keywords 258 | // http://eslint.org/docs/rules/no-useless-return 259 | 'no-useless-return': 'error', 260 | 261 | // disallow use of void operator 262 | // http://eslint.org/docs/rules/no-void 263 | 'no-void': 'error', 264 | 265 | // disallow usage of configurable warning terms in comments: e.g. todo 266 | 'no-warning-comments': ['off', { terms: ['todo', 'fixme', 'xxx'], location: 'start' }], 267 | 268 | // disallow use of the with statement 269 | 'no-with': 'error', 270 | 271 | // require using Error objects as Promise rejection reasons 272 | // http://eslint.org/docs/rules/prefer-promise-reject-errors 273 | // TODO: enable, semver-major 274 | 'prefer-promise-reject-errors': ['off', { allowEmptyReject: true }], 275 | 276 | // require use of the second argument for parseInt() 277 | radix: 'error', 278 | 279 | // require `await` in `async function` (note: this is a horrible rule that should never be used) 280 | // http://eslint.org/docs/rules/require-await 281 | 'require-await': 'off', 282 | 283 | // requires to declare all vars on top of their containing scope 284 | 'vars-on-top': 'error', 285 | 286 | // require immediate function invocation to be wrapped in parentheses 287 | // http://eslint.org/docs/rules/wrap-iife.html 288 | 'wrap-iife': ['error', 'outside', { functionPrototypeMethods: false }], 289 | 290 | // require or disallow Yoda conditions 291 | yoda: 'error' 292 | } 293 | }; 294 | -------------------------------------------------------------------------------- /packages/eslint-config-airbnb-base/rules/errors.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | rules: { 3 | // require trailing commas in multiline object literals 4 | 'comma-dangle': ['error', { 5 | arrays: 'always-multiline', 6 | objects: 'always-multiline', 7 | imports: 'always-multiline', 8 | exports: 'always-multiline', 9 | functions: 'always-multiline', 10 | }], 11 | 12 | // Enforce “for” loop update clause moving the counter in the right direction 13 | // http://eslint.org/docs/rules/for-direction 14 | // TODO: enable, semver-major until v3 is dropped; semver-minor otherwise 15 | 'for-direction': 'off', 16 | 17 | // Enforces that a return statement is present in property getters 18 | // http://eslint.org/docs/rules/getter-return 19 | // TODO: enable, semver-major when v3 is dropped 20 | 'getter-return': ['off', { allowImplicit: true }], 21 | 22 | // Disallow await inside of loops 23 | // http://eslint.org/docs/rules/no-await-in-loop 24 | 'no-await-in-loop': 'error', 25 | 26 | // Disallow comparisons to negative zero 27 | // http://eslint.org/docs/rules/no-compare-neg-zero 28 | // TODO: enable (semver-major) 29 | 'no-compare-neg-zero': 'off', 30 | 31 | // disallow assignment in conditional expressions 32 | 'no-cond-assign': ['error', 'always'], 33 | 34 | // disallow use of console 35 | 'no-console': 'warn', 36 | 37 | // disallow use of constant expressions in conditions 38 | 'no-constant-condition': 'warn', 39 | 40 | // disallow control characters in regular expressions 41 | 'no-control-regex': 'error', 42 | 43 | // disallow use of debugger 44 | 'no-debugger': 'error', 45 | 46 | // disallow duplicate arguments in functions 47 | 'no-dupe-args': 'error', 48 | 49 | // disallow duplicate keys when creating object literals 50 | 'no-dupe-keys': 'error', 51 | 52 | // disallow a duplicate case label. 53 | 'no-duplicate-case': 'error', 54 | 55 | // disallow empty statements 56 | 'no-empty': 'error', 57 | 58 | // disallow the use of empty character classes in regular expressions 59 | 'no-empty-character-class': 'error', 60 | 61 | // disallow assigning to the exception in a catch block 62 | 'no-ex-assign': 'error', 63 | 64 | // disallow double-negation boolean casts in a boolean context 65 | // http://eslint.org/docs/rules/no-extra-boolean-cast 66 | 'no-extra-boolean-cast': 'error', 67 | 68 | // disallow unnecessary parentheses 69 | // http://eslint.org/docs/rules/no-extra-parens 70 | 'no-extra-parens': ['off', 'all', { 71 | conditionalAssign: true, 72 | nestedBinaryExpressions: false, 73 | returnAssign: false, 74 | ignoreJSX: 'all', // delegate to eslint-plugin-react 75 | enforceForArrowConditionals: false, 76 | }], 77 | 78 | // disallow unnecessary semicolons 79 | 'no-extra-semi': 'error', 80 | 81 | // disallow overwriting functions written as function declarations 82 | 'no-func-assign': 'error', 83 | 84 | // disallow function or variable declarations in nested blocks 85 | 'no-inner-declarations': 'error', 86 | 87 | // disallow invalid regular expression strings in the RegExp constructor 88 | 'no-invalid-regexp': 'error', 89 | 90 | // disallow irregular whitespace outside of strings and comments 91 | 'no-irregular-whitespace': 'error', 92 | 93 | // disallow the use of object properties of the global object (Math and JSON) as functions 94 | 'no-obj-calls': 'error', 95 | 96 | // disallow use of Object.prototypes builtins directly 97 | // http://eslint.org/docs/rules/no-prototype-builtins 98 | 'no-prototype-builtins': 'error', 99 | 100 | // disallow multiple spaces in a regular expression literal 101 | 'no-regex-spaces': 'error', 102 | 103 | // disallow sparse arrays 104 | 'no-sparse-arrays': 'error', 105 | 106 | // Disallow template literal placeholder syntax in regular strings 107 | // http://eslint.org/docs/rules/no-template-curly-in-string 108 | 'no-template-curly-in-string': 'error', 109 | 110 | // Avoid code that looks like two expressions but is actually one 111 | // http://eslint.org/docs/rules/no-unexpected-multiline 112 | 'no-unexpected-multiline': 'error', 113 | 114 | // disallow unreachable statements after a return, throw, continue, or break statement 115 | 'no-unreachable': 'error', 116 | 117 | // disallow return/throw/break/continue inside finally blocks 118 | // http://eslint.org/docs/rules/no-unsafe-finally 119 | 'no-unsafe-finally': 'error', 120 | 121 | // disallow negating the left operand of relational operators 122 | // http://eslint.org/docs/rules/no-unsafe-negation 123 | 'no-unsafe-negation': 'error', 124 | // disallow negation of the left operand of an in expression 125 | // deprecated in favor of no-unsafe-negation 126 | 'no-negated-in-lhs': 'off', 127 | 128 | // disallow comparisons with the value NaN 129 | 'use-isnan': 'error', 130 | 131 | // ensure JSDoc comments are valid 132 | // http://eslint.org/docs/rules/valid-jsdoc 133 | 'valid-jsdoc': 'off', 134 | 135 | // ensure that the results of typeof are compared against a valid string 136 | // http://eslint.org/docs/rules/valid-typeof 137 | 'valid-typeof': ['error', { requireStringLiterals: true }], 138 | } 139 | }; 140 | -------------------------------------------------------------------------------- /packages/eslint-config-airbnb-base/rules/es6.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | es6: true 4 | }, 5 | parserOptions: { 6 | ecmaVersion: 6, 7 | sourceType: 'module', 8 | ecmaFeatures: { 9 | generators: false, 10 | objectLiteralDuplicateProperties: false 11 | } 12 | }, 13 | 14 | rules: { 15 | // enforces no braces where they can be omitted 16 | // http://eslint.org/docs/rules/arrow-body-style 17 | // TODO: enable requireReturnForObjectLiteral? 18 | 'arrow-body-style': ['error', 'as-needed', { 19 | requireReturnForObjectLiteral: false, 20 | }], 21 | 22 | // require parens in arrow function arguments 23 | // http://eslint.org/docs/rules/arrow-parens 24 | 'arrow-parens': ['error', 'as-needed', { 25 | requireForBlockBody: true, 26 | }], 27 | 28 | // require space before/after arrow function's arrow 29 | // http://eslint.org/docs/rules/arrow-spacing 30 | 'arrow-spacing': ['error', { before: true, after: true }], 31 | 32 | // verify super() callings in constructors 33 | 'constructor-super': 'error', 34 | 35 | // enforce the spacing around the * in generator functions 36 | // http://eslint.org/docs/rules/generator-star-spacing 37 | 'generator-star-spacing': ['error', { before: false, after: true }], 38 | 39 | // disallow modifying variables of class declarations 40 | // http://eslint.org/docs/rules/no-class-assign 41 | 'no-class-assign': 'error', 42 | 43 | // disallow arrow functions where they could be confused with comparisons 44 | // http://eslint.org/docs/rules/no-confusing-arrow 45 | 'no-confusing-arrow': ['error', { 46 | allowParens: true, 47 | }], 48 | 49 | // disallow modifying variables that are declared using const 50 | 'no-const-assign': 'error', 51 | 52 | // disallow duplicate class members 53 | // http://eslint.org/docs/rules/no-dupe-class-members 54 | 'no-dupe-class-members': 'error', 55 | 56 | // disallow importing from the same path more than once 57 | // http://eslint.org/docs/rules/no-duplicate-imports 58 | // replaced by https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-duplicates.md 59 | 'no-duplicate-imports': 'off', 60 | 61 | // disallow symbol constructor 62 | // http://eslint.org/docs/rules/no-new-symbol 63 | 'no-new-symbol': 'error', 64 | 65 | // disallow specific imports 66 | // http://eslint.org/docs/rules/no-restricted-imports 67 | 'no-restricted-imports': 'off', 68 | 69 | // disallow to use this/super before super() calling in constructors. 70 | // http://eslint.org/docs/rules/no-this-before-super 71 | 'no-this-before-super': 'error', 72 | 73 | // disallow useless computed property keys 74 | // http://eslint.org/docs/rules/no-useless-computed-key 75 | 'no-useless-computed-key': 'error', 76 | 77 | // disallow unnecessary constructor 78 | // http://eslint.org/docs/rules/no-useless-constructor 79 | 'no-useless-constructor': 'error', 80 | 81 | // disallow renaming import, export, and destructured assignments to the same name 82 | // http://eslint.org/docs/rules/no-useless-rename 83 | 'no-useless-rename': ['error', { 84 | ignoreDestructuring: false, 85 | ignoreImport: false, 86 | ignoreExport: false, 87 | }], 88 | 89 | // require let or const instead of var 90 | 'no-var': 'error', 91 | 92 | // require method and property shorthand syntax for object literals 93 | // http://eslint.org/docs/rules/object-shorthand 94 | 'object-shorthand': ['error', 'always', { 95 | ignoreConstructors: false, 96 | avoidQuotes: true, 97 | }], 98 | 99 | // suggest using arrow functions as callbacks 100 | 'prefer-arrow-callback': ['error', { 101 | allowNamedFunctions: false, 102 | allowUnboundThis: true, 103 | }], 104 | 105 | // suggest using of const declaration for variables that are never modified after declared 106 | 'prefer-const': ['error', { 107 | destructuring: 'any', 108 | ignoreReadBeforeAssign: true, 109 | }], 110 | 111 | // Prefer destructuring from arrays and objects 112 | // http://eslint.org/docs/rules/prefer-destructuring 113 | // TODO: enable 114 | 'prefer-destructuring': ['off', { 115 | VariableDeclarator: { 116 | array: false, 117 | object: true, 118 | }, 119 | AssignmentExpression: { 120 | array: true, 121 | object: true, 122 | }, 123 | }, { 124 | enforceForRenamedProperties: false, 125 | }], 126 | 127 | // disallow parseInt() in favor of binary, octal, and hexadecimal literals 128 | // http://eslint.org/docs/rules/prefer-numeric-literals 129 | 'prefer-numeric-literals': 'error', 130 | 131 | // suggest using Reflect methods where applicable 132 | // http://eslint.org/docs/rules/prefer-reflect 133 | 'prefer-reflect': 'off', 134 | 135 | // use rest parameters instead of arguments 136 | // http://eslint.org/docs/rules/prefer-rest-params 137 | 'prefer-rest-params': 'error', 138 | 139 | // suggest using the spread operator instead of .apply() 140 | // http://eslint.org/docs/rules/prefer-spread 141 | 'prefer-spread': 'error', 142 | 143 | // suggest using template literals instead of string concatenation 144 | // http://eslint.org/docs/rules/prefer-template 145 | 'prefer-template': 'error', 146 | 147 | // disallow generator functions that do not have yield 148 | // http://eslint.org/docs/rules/require-yield 149 | 'require-yield': 'error', 150 | 151 | // enforce spacing between object rest-spread 152 | // http://eslint.org/docs/rules/rest-spread-spacing 153 | 'rest-spread-spacing': ['error', 'never'], 154 | 155 | // import sorting 156 | // http://eslint.org/docs/rules/sort-imports 157 | 'sort-imports': ['off', { 158 | ignoreCase: false, 159 | ignoreMemberSort: false, 160 | memberSyntaxSortOrder: ['none', 'all', 'multiple', 'single'], 161 | }], 162 | 163 | // require a Symbol description 164 | // http://eslint.org/docs/rules/symbol-description 165 | 'symbol-description': 'error', 166 | 167 | // enforce usage of spacing in template strings 168 | // http://eslint.org/docs/rules/template-curly-spacing 169 | 'template-curly-spacing': 'error', 170 | 171 | // enforce spacing around the * in yield* expressions 172 | // http://eslint.org/docs/rules/yield-star-spacing 173 | 'yield-star-spacing': ['error', 'after'] 174 | } 175 | }; 176 | -------------------------------------------------------------------------------- /packages/eslint-config-airbnb-base/rules/imports.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | es6: true 4 | }, 5 | parserOptions: { 6 | ecmaVersion: 6, 7 | sourceType: 'module' 8 | }, 9 | plugins: [ 10 | 'import' 11 | ], 12 | 13 | settings: { 14 | 'import/resolver': { 15 | node: { 16 | extensions: ['.js', '.json'] 17 | } 18 | }, 19 | 'import/extensions': [ 20 | '.js', 21 | '.jsx', 22 | ], 23 | 'import/core-modules': [ 24 | ], 25 | 'import/ignore': [ 26 | 'node_modules', 27 | '\\.(coffee|scss|css|less|hbs|svg|json)$', 28 | ], 29 | }, 30 | 31 | rules: { 32 | // Static analysis: 33 | 34 | // ensure imports point to files/modules that can be resolved 35 | // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-unresolved.md 36 | 'import/no-unresolved': ['error', { commonjs: true, caseSensitive: true }], 37 | 38 | // ensure named imports coupled with named exports 39 | // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/named.md#when-not-to-use-it 40 | 'import/named': 'off', 41 | 42 | // ensure default import coupled with default export 43 | // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/default.md#when-not-to-use-it 44 | 'import/default': 'off', 45 | 46 | // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/namespace.md 47 | 'import/namespace': 'off', 48 | 49 | // Helpful warnings: 50 | 51 | // disallow invalid exports, e.g. multiple defaults 52 | // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/export.md 53 | 'import/export': 'error', 54 | 55 | // do not allow a default import name to match a named export 56 | // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-named-as-default.md 57 | 'import/no-named-as-default': 'error', 58 | 59 | // warn on accessing default export property names that are also named exports 60 | // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-named-as-default-member.md 61 | 'import/no-named-as-default-member': 'error', 62 | 63 | // disallow use of jsdoc-marked-deprecated imports 64 | // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-deprecated.md 65 | 'import/no-deprecated': 'off', 66 | 67 | // Forbid the use of extraneous packages 68 | // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-extraneous-dependencies.md 69 | // paths are treated both as absolute paths, and relative to process.cwd() 70 | 'import/no-extraneous-dependencies': ['error', { 71 | devDependencies: [ 72 | 'test/**', // tape, common npm pattern 73 | 'tests/**', // also common npm pattern 74 | 'spec/**', // mocha, rspec-like pattern 75 | '**/__tests__/**', // jest pattern 76 | 'test.{js,jsx}', // repos with a single test file 77 | 'test-*.{js,jsx}', // repos with multiple top-level test files 78 | '**/*.{test,spec}.{js,jsx}', // tests where the extension denotes that it is a test 79 | '**/webpack.config.js', // webpack config 80 | '**/webpack.config.*.js', // webpack config 81 | '**/rollup.config.js', // rollup config 82 | '**/rollup.config.*.js', // rollup config 83 | '**/gulpfile.js', // gulp config 84 | '**/gulpfile.*.js', // gulp config 85 | '**/Gruntfile', // grunt config 86 | '**/protractor.conf.*.js', // protractor config 87 | ], 88 | optionalDependencies: false, 89 | }], 90 | 91 | // Forbid mutable exports 92 | // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-mutable-exports.md 93 | 'import/no-mutable-exports': 'error', 94 | 95 | // Module systems: 96 | 97 | // disallow require() 98 | // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-commonjs.md 99 | 'import/no-commonjs': 'off', 100 | 101 | // disallow AMD require/define 102 | // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-amd.md 103 | 'import/no-amd': 'error', 104 | 105 | // No Node.js builtin modules 106 | // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-nodejs-modules.md 107 | // TODO: enable? 108 | 'import/no-nodejs-modules': 'off', 109 | 110 | // Style guide: 111 | 112 | // disallow non-import statements appearing before import statements 113 | // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/first.md 114 | 'import/first': ['error', 'absolute-first'], 115 | 116 | // disallow non-import statements appearing before import statements 117 | // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/imports-first.md 118 | // deprecated: use `import/first` 119 | 'import/imports-first': 'off', 120 | 121 | // disallow duplicate imports 122 | // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-duplicates.md 123 | 'import/no-duplicates': 'error', 124 | 125 | // disallow namespace imports 126 | // TODO: enable? 127 | // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-namespace.md 128 | 'import/no-namespace': 'off', 129 | 130 | // Ensure consistent use of file extension within the import path 131 | // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/extensions.md 132 | 'import/extensions': ['error', 'always', { 133 | js: 'never', 134 | jsx: 'never', 135 | }], 136 | 137 | // Enforce a convention in module import order 138 | // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/order.md 139 | // TODO: enable? 140 | 'import/order': ['off', { 141 | groups: ['builtin', 'external', 'internal', 'parent', 'sibling', 'index'], 142 | 'newlines-between': 'never', 143 | }], 144 | 145 | // Require a newline after the last import/require in a group 146 | // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/newline-after-import.md 147 | 'import/newline-after-import': 'error', 148 | 149 | // Require modules with a single export to use a default export 150 | // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/prefer-default-export.md 151 | 'import/prefer-default-export': 'error', 152 | 153 | // Restrict which files can be imported in a given folder 154 | // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-restricted-paths.md 155 | 'import/no-restricted-paths': 'off', 156 | 157 | // Forbid modules to have too many dependencies 158 | // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/max-dependencies.md 159 | 'import/max-dependencies': ['off', { max: 10 }], 160 | 161 | // Forbid import of modules using absolute paths 162 | // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-absolute-path.md 163 | 'import/no-absolute-path': 'error', 164 | 165 | // Forbid require() calls with expressions 166 | // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-dynamic-require.md 167 | 'import/no-dynamic-require': 'error', 168 | 169 | // prevent importing the submodules of other modules 170 | // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-internal-modules.md 171 | 'import/no-internal-modules': ['off', { 172 | allow: [], 173 | }], 174 | 175 | // Warn if a module could be mistakenly parsed as a script by a consumer 176 | // leveraging Unambiguous JavaScript Grammar 177 | // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/unambiguous.md 178 | // this should not be enabled until this proposal has at least been *presented* to TC39. 179 | // At the moment, it's not a thing. 180 | 'import/unambiguous': 'off', 181 | 182 | // Forbid Webpack loader syntax in imports 183 | // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-webpack-loader-syntax.md 184 | 'import/no-webpack-loader-syntax': 'error', 185 | 186 | // Prevent unassigned imports 187 | // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-unassigned-import.md 188 | // importing for side effects is perfectly acceptable, if you need side effects. 189 | 'import/no-unassigned-import': 'off', 190 | 191 | // Prevent importing the default as if it were named 192 | // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-named-default.md 193 | 'import/no-named-default': 'error', 194 | 195 | // Reports if a module's default export is unnamed 196 | // https://github.com/benmosher/eslint-plugin-import/blob/d9b712ac7fd1fddc391f7b234827925c160d956f/docs/rules/no-anonymous-default-export.md 197 | 'import/no-anonymous-default-export': ['off', { 198 | allowArray: false, 199 | allowArrowFunction: false, 200 | allowAnonymousClass: false, 201 | allowAnonymousFunction: false, 202 | allowLiteral: false, 203 | allowObject: false, 204 | }], 205 | }, 206 | }; 207 | -------------------------------------------------------------------------------- /packages/eslint-config-airbnb-base/rules/node.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | node: true 4 | }, 5 | 6 | rules: { 7 | // enforce return after a callback 8 | 'callback-return': 'off', 9 | 10 | // require all requires be top-level 11 | // http://eslint.org/docs/rules/global-require 12 | 'global-require': 'error', 13 | 14 | // enforces error handling in callbacks (node environment) 15 | 'handle-callback-err': 'off', 16 | 17 | // disallow use of the Buffer() constructor 18 | // http://eslint.org/docs/rules/no-buffer-constructor 19 | // TODO: enable, semver-major 20 | 'no-buffer-constructor': 'off', 21 | 22 | // disallow mixing regular variable and require declarations 23 | 'no-mixed-requires': ['off', false], 24 | 25 | // disallow use of new operator with the require function 26 | 'no-new-require': 'error', 27 | 28 | // disallow string concatenation with __dirname and __filename 29 | // http://eslint.org/docs/rules/no-path-concat 30 | 'no-path-concat': 'error', 31 | 32 | // disallow use of process.env 33 | 'no-process-env': 'off', 34 | 35 | // disallow process.exit() 36 | 'no-process-exit': 'off', 37 | 38 | // restrict usage of specified node modules 39 | 'no-restricted-modules': 'off', 40 | 41 | // disallow use of synchronous methods (off by default) 42 | 'no-sync': 'off', 43 | } 44 | }; 45 | -------------------------------------------------------------------------------- /packages/eslint-config-airbnb-base/rules/strict.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | rules: { 3 | // babel inserts `'use strict';` for us 4 | strict: ['error', 'never'] 5 | } 6 | }; 7 | -------------------------------------------------------------------------------- /packages/eslint-config-airbnb-base/rules/style.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | rules: { 3 | // enforce line breaks after opening and before closing array brackets 4 | // http://eslint.org/docs/rules/array-bracket-newline 5 | // TODO: enable? semver-major 6 | 'array-bracket-newline': ['off', { multiline: true, minItems: 3 }], 7 | 8 | // enforce line breaks between array elements 9 | // http://eslint.org/docs/rules/array-element-newline 10 | // TODO: enable? semver-major 11 | 'array-element-newline': ['off', { multiline: true, minItems: 3 }], 12 | 13 | // enforce spacing inside array brackets 14 | 'array-bracket-spacing': ['error', 'never'], 15 | 16 | // enforce spacing inside single-line blocks 17 | // http://eslint.org/docs/rules/block-spacing 18 | 'block-spacing': ['error', 'always'], 19 | 20 | // enforce one true brace style 21 | 'brace-style': ['error', '1tbs', { allowSingleLine: true }], 22 | 23 | // require camel case names 24 | camelcase: ['error', { properties: 'never' }], 25 | 26 | // enforce or disallow capitalization of the first letter of a comment 27 | // http://eslint.org/docs/rules/capitalized-comments 28 | 'capitalized-comments': ['off', 'never', { 29 | line: { 30 | ignorePattern: '.*', 31 | ignoreInlineComments: true, 32 | ignoreConsecutiveComments: true, 33 | }, 34 | block: { 35 | ignorePattern: '.*', 36 | ignoreInlineComments: true, 37 | ignoreConsecutiveComments: true, 38 | }, 39 | }], 40 | 41 | // enforce spacing before and after comma 42 | 'comma-spacing': ['error', { before: false, after: true }], 43 | 44 | // enforce one true comma style 45 | 'comma-style': ['error', 'last'], 46 | 47 | // disallow padding inside computed properties 48 | 'computed-property-spacing': ['error', 'never'], 49 | 50 | // enforces consistent naming when capturing the current execution context 51 | 'consistent-this': 'off', 52 | 53 | // enforce newline at the end of file, with no multiple empty lines 54 | 'eol-last': ['error', 'always'], 55 | 56 | // enforce spacing between functions and their invocations 57 | // http://eslint.org/docs/rules/func-call-spacing 58 | 'func-call-spacing': ['error', 'never'], 59 | 60 | // requires function names to match the name of the variable or property to which they are 61 | // assigned 62 | // http://eslint.org/docs/rules/func-name-matching 63 | 'func-name-matching': ['off', 'always', { 64 | includeCommonJSModuleExports: false 65 | }], 66 | 67 | // require function expressions to have a name 68 | // http://eslint.org/docs/rules/func-names 69 | 'func-names': 'warn', 70 | 71 | // enforces use of function declarations or expressions 72 | // http://eslint.org/docs/rules/func-style 73 | // TODO: enable 74 | 'func-style': ['off', 'expression'], 75 | 76 | // Blacklist certain identifiers to prevent them being used 77 | // http://eslint.org/docs/rules/id-blacklist 78 | 'id-blacklist': 'off', 79 | 80 | // this option enforces minimum and maximum identifier lengths 81 | // (variable names, property names etc.) 82 | 'id-length': 'off', 83 | 84 | // require identifiers to match the provided regular expression 85 | 'id-match': 'off', 86 | 87 | // this option sets a specific tab width for your code 88 | // http://eslint.org/docs/rules/indent 89 | indent: ['error', 2, { 90 | SwitchCase: 1, 91 | VariableDeclarator: 1, 92 | outerIIFEBody: 1, 93 | // MemberExpression: null, 94 | // CallExpression: { 95 | // parameters: null, 96 | // }, 97 | FunctionDeclaration: { 98 | parameters: 1, 99 | body: 1 100 | }, 101 | FunctionExpression: { 102 | parameters: 1, 103 | body: 1 104 | } 105 | }], 106 | 107 | // specify whether double or single quotes should be used in JSX attributes 108 | // http://eslint.org/docs/rules/jsx-quotes 109 | 'jsx-quotes': ['off', 'prefer-double'], 110 | 111 | // enforces spacing between keys and values in object literal properties 112 | 'key-spacing': ['error', { beforeColon: false, afterColon: true }], 113 | 114 | // require a space before & after certain keywords 115 | 'keyword-spacing': ['error', { 116 | before: true, 117 | after: true, 118 | overrides: { 119 | return: { after: true }, 120 | throw: { after: true }, 121 | case: { after: true } 122 | } 123 | }], 124 | 125 | // enforce position of line comments 126 | // http://eslint.org/docs/rules/line-comment-position 127 | // TODO: enable? 128 | 'line-comment-position': ['off', { 129 | position: 'above', 130 | ignorePattern: '', 131 | applyDefaultPatterns: true, 132 | }], 133 | 134 | // disallow mixed 'LF' and 'CRLF' as linebreaks 135 | // http://eslint.org/docs/rules/linebreak-style 136 | 'linebreak-style': ['error', 'unix'], 137 | 138 | // enforces empty lines around comments 139 | 'lines-around-comment': 'off', 140 | 141 | // require or disallow newlines around directives 142 | // http://eslint.org/docs/rules/lines-around-directive 143 | 'lines-around-directive': ['error', { 144 | before: 'always', 145 | after: 'always', 146 | }], 147 | 148 | // specify the maximum depth that blocks can be nested 149 | 'max-depth': ['off', 4], 150 | 151 | // specify the maximum length of a line in your program 152 | // http://eslint.org/docs/rules/max-len 153 | 'max-len': ['error', 100, 2, { 154 | ignoreUrls: true, 155 | ignoreComments: false, 156 | ignoreRegExpLiterals: true, 157 | ignoreStrings: true, 158 | ignoreTemplateLiterals: true, 159 | }], 160 | 161 | // specify the max number of lines in a file 162 | // http://eslint.org/docs/rules/max-lines 163 | 'max-lines': ['off', { 164 | max: 300, 165 | skipBlankLines: true, 166 | skipComments: true 167 | }], 168 | 169 | // specify the maximum depth callbacks can be nested 170 | 'max-nested-callbacks': 'off', 171 | 172 | // limits the number of parameters that can be used in the function declaration. 173 | 'max-params': ['off', 3], 174 | 175 | // specify the maximum number of statement allowed in a function 176 | 'max-statements': ['off', 10], 177 | 178 | // restrict the number of statements per line 179 | // http://eslint.org/docs/rules/max-statements-per-line 180 | 'max-statements-per-line': ['off', { max: 1 }], 181 | 182 | // require multiline ternary 183 | // http://eslint.org/docs/rules/multiline-ternary 184 | // TODO: enable? 185 | 'multiline-ternary': ['off', 'never'], 186 | 187 | // require a capital letter for constructors 188 | 'new-cap': ['error', { 189 | newIsCap: true, 190 | newIsCapExceptions: [], 191 | capIsNew: false, 192 | capIsNewExceptions: ['Immutable.Map', 'Immutable.Set', 'Immutable.List'], 193 | }], 194 | 195 | // disallow the omission of parentheses when invoking a constructor with no arguments 196 | // http://eslint.org/docs/rules/new-parens 197 | 'new-parens': 'error', 198 | 199 | // allow/disallow an empty newline after var statement 200 | 'newline-after-var': 'off', 201 | 202 | // http://eslint.org/docs/rules/newline-before-return 203 | 'newline-before-return': 'off', 204 | 205 | // enforces new line after each method call in the chain to make it 206 | // more readable and easy to maintain 207 | // http://eslint.org/docs/rules/newline-per-chained-call 208 | 'newline-per-chained-call': ['error', { ignoreChainWithDepth: 4 }], 209 | 210 | // disallow use of the Array constructor 211 | 'no-array-constructor': 'error', 212 | 213 | // disallow use of bitwise operators 214 | // http://eslint.org/docs/rules/no-bitwise 215 | 'no-bitwise': 'error', 216 | 217 | // disallow use of the continue statement 218 | // http://eslint.org/docs/rules/no-continue 219 | 'no-continue': 'error', 220 | 221 | // disallow comments inline after code 222 | 'no-inline-comments': 'off', 223 | 224 | // disallow if as the only statement in an else block 225 | // http://eslint.org/docs/rules/no-lonely-if 226 | 'no-lonely-if': 'error', 227 | 228 | // disallow un-paren'd mixes of different operators 229 | // http://eslint.org/docs/rules/no-mixed-operators 230 | 'no-mixed-operators': ['error', { 231 | groups: [ 232 | ['+', '-', '*', '/', '%', '**'], 233 | ['&', '|', '^', '~', '<<', '>>', '>>>'], 234 | ['==', '!=', '===', '!==', '>', '>=', '<', '<='], 235 | ['&&', '||'], 236 | ['in', 'instanceof'] 237 | ], 238 | allowSamePrecedence: false 239 | }], 240 | 241 | // disallow mixed spaces and tabs for indentation 242 | 'no-mixed-spaces-and-tabs': 'error', 243 | 244 | // disallow use of chained assignment expressions 245 | // http://eslint.org/docs/rules/no-multi-assign 246 | 'no-multi-assign': ['error'], 247 | 248 | // disallow multiple empty lines and only one newline at the end 249 | 'no-multiple-empty-lines': ['error', { max: 2, maxEOF: 1 }], 250 | 251 | // disallow negated conditions 252 | // http://eslint.org/docs/rules/no-negated-condition 253 | 'no-negated-condition': 'off', 254 | 255 | // disallow nested ternary expressions 256 | 'no-nested-ternary': 'error', 257 | 258 | // disallow use of the Object constructor 259 | 'no-new-object': 'error', 260 | 261 | // disallow use of unary operators, ++ and -- 262 | // http://eslint.org/docs/rules/no-plusplus 263 | 'no-plusplus': 'error', 264 | 265 | // disallow certain syntax forms 266 | // http://eslint.org/docs/rules/no-restricted-syntax 267 | 'no-restricted-syntax': [ 268 | 'error', 269 | { 270 | selector: 'ForInStatement', 271 | message: 'for..in loops iterate over the entire prototype chain, which is virtually never what you want. Use Object.{keys,values,entries}, and iterate over the resulting array.', 272 | }, 273 | { 274 | selector: 'ForOfStatement', 275 | message: 'iterators/generators require regenerator-runtime, which is too heavyweight for this guide to allow them. Separately, loops should be avoided in favor of array iterations.', 276 | }, 277 | { 278 | selector: 'LabeledStatement', 279 | message: 'Labels are a form of GOTO; using them makes code confusing and hard to maintain and understand.', 280 | }, 281 | { 282 | selector: 'WithStatement', 283 | message: '`with` is disallowed in strict mode because it makes code impossible to predict and optimize.', 284 | }, 285 | ], 286 | 287 | // disallow space between function identifier and application 288 | 'no-spaced-func': 'error', 289 | 290 | // disallow tab characters entirely 291 | 'no-tabs': 'error', 292 | 293 | // disallow the use of ternary operators 294 | 'no-ternary': 'off', 295 | 296 | // disallow trailing whitespace at the end of lines 297 | 'no-trailing-spaces': ['error', { 298 | skipBlankLines: false, 299 | // ignoreComments: false, // TODO: uncomment once v3 is dropped 300 | }], 301 | 302 | // disallow dangling underscores in identifiers 303 | 'no-underscore-dangle': ['error', { 304 | allow: [], 305 | allowAfterThis: false, 306 | allowAfterSuper: false, 307 | // enforceInMethodNames: false, // TODO: uncoment and enable, semver-minor once v3 is dropped 308 | }], 309 | 310 | // disallow the use of Boolean literals in conditional expressions 311 | // also, prefer `a || b` over `a ? a : b` 312 | // http://eslint.org/docs/rules/no-unneeded-ternary 313 | 'no-unneeded-ternary': ['error', { defaultAssignment: false }], 314 | 315 | // disallow whitespace before properties 316 | // http://eslint.org/docs/rules/no-whitespace-before-property 317 | 'no-whitespace-before-property': 'error', 318 | 319 | // enforce the location of single-line statements 320 | // http://eslint.org/docs/rules/nonblock-statement-body-position 321 | 'nonblock-statement-body-position': 'off', 322 | 323 | // require padding inside curly braces 324 | 'object-curly-spacing': ['error', 'always'], 325 | 326 | // enforce line breaks between braces 327 | // http://eslint.org/docs/rules/object-curly-newline 328 | // TODO: enable once https://github.com/eslint/eslint/issues/6488 is resolved and v3 is dropped 329 | 'object-curly-newline': ['off', { 330 | ObjectExpression: { minProperties: 3, multiline: true, consistent: true }, 331 | ObjectPattern: { minProperties: 3, multiline: true, consistent: true } 332 | }], 333 | 334 | // enforce "same line" or "multiple line" on object properties. 335 | // http://eslint.org/docs/rules/object-property-newline 336 | 'object-property-newline': ['error', { 337 | allowMultiplePropertiesPerLine: true, 338 | }], 339 | 340 | // allow just one var statement per function 341 | 'one-var': ['error', 'never'], 342 | 343 | // require a newline around variable declaration 344 | // http://eslint.org/docs/rules/one-var-declaration-per-line 345 | 'one-var-declaration-per-line': ['error', 'always'], 346 | 347 | // require assignment operator shorthand where possible or prohibit it entirely 348 | // http://eslint.org/docs/rules/operator-assignment 349 | 'operator-assignment': ['error', 'always'], 350 | 351 | // enforce operators to be placed before or after line breaks 352 | 'operator-linebreak': 'off', 353 | 354 | // enforce padding within blocks 355 | 'padded-blocks': ['error', 'never'], 356 | 357 | // Require or disallow padding lines between statements 358 | // http://eslint.org/docs/rules/padding-line-between-statements 359 | 'padding-line-between-statements': 'off', 360 | 361 | // require quotes around object literal property names 362 | // http://eslint.org/docs/rules/quote-props.html 363 | 'quote-props': ['error', 'as-needed', { keywords: false, unnecessary: true, numbers: false }], 364 | 365 | // specify whether double or single quotes should be used 366 | quotes: ['error', 'single', { avoidEscape: true }], 367 | 368 | // do not require jsdoc 369 | // http://eslint.org/docs/rules/require-jsdoc 370 | 'require-jsdoc': 'off', 371 | 372 | // require or disallow use of semicolons instead of ASI 373 | semi: ['error', 'always'], 374 | 375 | // enforce spacing before and after semicolons 376 | 'semi-spacing': ['error', { before: false, after: true }], 377 | 378 | // Enforce location of semicolons 379 | // http://eslint.org/docs/rules/semi-style 380 | // TODO: enable, semver-major until v3 is dropped, semver-minor otherwise 381 | 'semi-style': ['off', 'last'], 382 | 383 | // requires object keys to be sorted 384 | 'sort-keys': ['off', 'asc', { caseSensitive: false, natural: true }], 385 | 386 | // sort variables within the same declaration block 387 | 'sort-vars': 'off', 388 | 389 | // require or disallow space before blocks 390 | 'space-before-blocks': 'error', 391 | 392 | // require or disallow space before function opening parenthesis 393 | // http://eslint.org/docs/rules/space-before-function-paren 394 | 'space-before-function-paren': ['error', { 395 | anonymous: 'always', 396 | named: 'never', 397 | asyncArrow: 'always' 398 | }], 399 | 400 | // require or disallow spaces inside parentheses 401 | 'space-in-parens': ['error', 'never'], 402 | 403 | // require spaces around operators 404 | 'space-infix-ops': 'error', 405 | 406 | // Require or disallow spaces before/after unary operators 407 | // http://eslint.org/docs/rules/space-unary-ops 408 | 'space-unary-ops': ['error', { 409 | words: true, 410 | nonwords: false, 411 | overrides: { 412 | }, 413 | }], 414 | 415 | // require or disallow a space immediately following the // or /* in a comment 416 | // http://eslint.org/docs/rules/spaced-comment 417 | 'spaced-comment': ['error', 'always', { 418 | line: { 419 | exceptions: ['-', '+'], 420 | markers: ['=', '!'], // space here to support sprockets directives 421 | }, 422 | block: { 423 | exceptions: ['-', '+'], 424 | markers: ['=', '!'], // space here to support sprockets directives 425 | balanced: true, 426 | } 427 | }], 428 | 429 | // Enforce spacing around colons of switch statements 430 | // http://eslint.org/docs/rules/switch-colon-spacing 431 | // TODO: enable, semver-major 432 | 'switch-colon-spacing': ['off', { after: true, before: false }], 433 | 434 | // Require or disallow spacing between template tags and their literals 435 | // http://eslint.org/docs/rules/template-tag-spacing 436 | // TODO: enable, semver-major 437 | 'template-tag-spacing': ['off', 'never'], 438 | 439 | // require or disallow the Unicode Byte Order Mark 440 | // http://eslint.org/docs/rules/unicode-bom 441 | 'unicode-bom': ['error', 'never'], 442 | 443 | // require regex literals to be wrapped in parentheses 444 | 'wrap-regex': 'off' 445 | } 446 | }; 447 | -------------------------------------------------------------------------------- /packages/eslint-config-airbnb-base/rules/variables.js: -------------------------------------------------------------------------------- 1 | const restrictedGlobals = require('eslint-restricted-globals'); 2 | 3 | module.exports = { 4 | rules: { 5 | // enforce or disallow variable initializations at definition 6 | 'init-declarations': 'off', 7 | 8 | // disallow the catch clause parameter name being the same as a variable in the outer scope 9 | 'no-catch-shadow': 'off', 10 | 11 | // disallow deletion of variables 12 | 'no-delete-var': 'error', 13 | 14 | // disallow labels that share a name with a variable 15 | // http://eslint.org/docs/rules/no-label-var 16 | 'no-label-var': 'error', 17 | 18 | // disallow specific globals 19 | // TODO: enable, semver-major 20 | 'no-restricted-globals': ['off'].concat(restrictedGlobals), 21 | 22 | // disallow declaration of variables already declared in the outer scope 23 | 'no-shadow': 'error', 24 | 25 | // disallow shadowing of names such as arguments 26 | 'no-shadow-restricted-names': 'error', 27 | 28 | // disallow use of undeclared variables unless mentioned in a /*global */ block 29 | 'no-undef': 'error', 30 | 31 | // disallow use of undefined when initializing variables 32 | 'no-undef-init': 'error', 33 | 34 | // disallow use of undefined variable 35 | // http://eslint.org/docs/rules/no-undefined 36 | // TODO: enable? 37 | 'no-undefined': 'off', 38 | 39 | // disallow declaration of variables that are not used in the code 40 | 'no-unused-vars': ['error', { vars: 'all', args: 'after-used', ignoreRestSiblings: true }], 41 | 42 | // disallow use of variables before they are defined 43 | 'no-use-before-define': ['error', { functions: true, classes: true, variables: true }], 44 | } 45 | }; 46 | -------------------------------------------------------------------------------- /packages/eslint-config-airbnb-base/test/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | // disabled because I find it tedious to write tests while following this rule 4 | "no-shadow": 0, 5 | // tests uses `t` for tape 6 | "id-length": [2, {"min": 2, "properties": "never", "exceptions": ["t"]}], 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /packages/eslint-config-airbnb-base/test/test-base.js: -------------------------------------------------------------------------------- 1 | import fs from 'fs'; 2 | import path from 'path'; 3 | import test from 'tape'; 4 | 5 | import index from '../'; 6 | 7 | const files = { ...{ index } }; // object spread is to test parsing 8 | 9 | fs.readdirSync(path.join(__dirname, '../rules')).forEach((name) => { 10 | // eslint-disable-next-line import/no-dynamic-require 11 | files[name] = require(`../rules/${name}`); // eslint-disable-line global-require 12 | }); 13 | 14 | Object.keys(files).forEach(( 15 | name, // trailing function comma is to test parsing 16 | ) => { 17 | const config = files[name]; 18 | 19 | test(`${name}: does not reference react`, (t) => { 20 | t.plan(2); 21 | 22 | // scan plugins for react and fail if it is found 23 | const hasReactPlugin = Object.prototype.hasOwnProperty.call(config, 'plugins') && 24 | config.plugins.indexOf('react') !== -1; 25 | t.notOk(hasReactPlugin, 'there is no react plugin'); 26 | 27 | // scan rules for react/ and fail if any exist 28 | const reactRuleIds = Object.keys(config.rules) 29 | .filter(ruleId => ruleId.indexOf('react/') === 0); 30 | t.deepEquals(reactRuleIds, [], 'there are no react/ rules'); 31 | }); 32 | }); 33 | -------------------------------------------------------------------------------- /packages/eslint-config-airbnb/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["airbnb"] 3 | } 4 | -------------------------------------------------------------------------------- /packages/eslint-config-airbnb/.editorconfig: -------------------------------------------------------------------------------- 1 | ../../.editorconfig -------------------------------------------------------------------------------- /packages/eslint-config-airbnb/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./index.js", 3 | "rules": { 4 | // disable requiring trailing commas because it might be nice to revert to 5 | // being JSON at some point, and I don't want to make big changes now. 6 | "comma-dangle": 0 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /packages/eslint-config-airbnb/.npmrc: -------------------------------------------------------------------------------- 1 | ../../.npmrc -------------------------------------------------------------------------------- /packages/eslint-config-airbnb/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 15.1.0 / 2017-07-24 2 | ================== 3 | - [deps] allow eslint v3 or v4 (#1447) 4 | - [deps] update `eslint-plugin-import`, `eslint-config-airbnb-base` 5 | 6 | 15.0.2 / 2017-07-04 7 | ================== 8 | - [fix] jsx should be enabled via parserOptions, not via a root ecmaFeatures 9 | - [deps] update `babel-preset-airbnb`, `eslint-find-rules`, `eslint-plugin-import`, `eslint-plugin-jsx-a11y`, `eslint-plugin-react`, `tape` 10 | 11 | 15.0.1 / 2017-05-15 12 | ================== 13 | - [fix] set default React version to 15.0 (#1415) 14 | 15 | 15.0.0 / 2017-05-14 16 | ================== 17 | - [breaking] set default React version to 0.15 18 | - [breaking] `update eslint-plugin-jsx-a11y` to v5, enable new rules 19 | - [breaking] `update eslint-plugin-react` to v7, enable new rules 20 | - [minor] enable rules: `jsx-max-props-per-line`, `void-dom-elements-no-children` 21 | - [patch] Turn `ignorePureComponents` option on for react/prefer-stateless-function (#1378, #1398) 22 | - [deps] update `eslint`, `eslint-plugin-react`, `eslint-config-airbnb-base` 23 | 24 | 14.1.0 / 2017-02-05 25 | ================== 26 | - [patch] allow `eslint-plugin-jsx-a11y` to be v3 or v4. Remove `no-marquee` rule temporarily. 27 | - [deps] update `eslint-config-airbnb-base`, `babel-preset-airbnb`, `eslint` 28 | 29 | 14.0.0 / 2017-01-08 30 | ================== 31 | - [breaking] enable `react/no-array-index-key`, `react/require-default-props` 32 | - [breaking] [deps] update `eslint`, `eslint-plugin-import`, `eslint-plugin-react`, `eslint-config-airbnb-base` 33 | - [breaking] [deps] update `eslint-plugin-jsx-a11y` to v3 (#1166) 34 | - [docs] add note about `install-peerdeps` (#1234) 35 | - [docs] Updated instructions to support non-bash users (#1214) 36 | 37 | 13.0.0 / 2016-11-06 38 | ================== 39 | - [breaking] Enable `import/no-webpack-loader-syntax` rule (#1123) 40 | - [patch] `class-methods-use-this`: exempt React `getChildContext` (#1094) 41 | - [patch] set `react/no-unused-prop-types` skipShapeProps (#1099) 42 | - [deps] [breaking] update `eslint`, `eslint-config-airbnb-base`, `eslint-plugin-jsx-a11y`, `eslint-plugin-react`, `eslint-plugin-import` 43 | - [dev deps] update `babel-preset-airbnb`, `eslint`, `eslint-find-rules`, `tape`, `safe-publish-latest` 44 | - [Tests] on `node` `v7` 45 | - [docs] ensure latest version of config is installed (#1121) 46 | 47 | 12.0.0 / 2016-09-24 48 | ================== 49 | - [breaking] Enable react rules: `react/no-unescaped-entities`, `react/no-children-prop` 50 | - [breaking] [deps] update `eslint-config-airbnb-base` 51 | - [patch] disable deprecated and redundant `react/require-extension` rule (#978) 52 | 53 | 11.2.0 / 2016-09-23 54 | ================== 55 | - [new] set `ecmaVersion` to 2017; enable object rest/spread; update `babel-preset-airbnb` 56 | - [deps] update `eslint`, `eslint-config-airbnb-base`, `eslint-plugin-import`, `eslint-plugin-jsx-a11y`, `eslint-plugin-react`, `eslint-find-rules`, `safe-publish-latest` 57 | 58 | 11.1.0 / 2016-09-11 59 | ================== 60 | - [deps] update `eslint-config-airbnb-base`, `eslint` 61 | 62 | 11.0.0 / 2016-09-08 63 | ================== 64 | - [breaking] enable `react` rules: `react/no-danger-with-children`, `react/no-unused-prop-types`, `react/style-prop-object`, `react/forbid-prop-types`, `react/jsx-no-duplicate-props`; set `react/no-danger` to “warn” 65 | - [breaking] enable `jsx-a11y` rules: `jsx-a11y/anchor-has-content`, `jsx-a11y/tabindex-no-positive`, `jsx-a11y/no-static-element-interactions` 66 | - [deps] update `eslint`, `eslint-plugin-react`, `eslint-config-airbnb-base`, `eslint-find-rules`, `eslint-plugin-import`, `eslint-plugin-jsx-a11y` 67 | - [patch] set `ignoreCase` to `true` in disabled rules. 68 | - [docs] use “#” in example command rather than version numbers (#984) 69 | 70 | 10.0.1 / 2016-08-12 71 | ================== 72 | - [deps] update `eslint`, `eslint-find-rules`, `eslint-plugin-jsx-a11y`, `eslint-plugin-import`, `eslint-config-airbnb-base` 73 | 74 | 10.0.0 / 2016-08-01 75 | ================== 76 | - [breaking] enable jsx-a11y rules: 77 | - `jsx-a11y/heading-has-content` 78 | - `jsx-a11y/html-has-lang` 79 | - `jsx-a11y/lang` 80 | - `jsx-a11y/no-marquee` 81 | - `jsx-a11y/scope` 82 | - `jsx-a11y/href-no-hash` 83 | - `jsx-a11y/label-has-for` 84 | - [breaking] enable aria rules: 85 | - `jsx-a11y/aria-props` 86 | - `jsx-a11y/aria-proptypes` 87 | - `jsx-a11y/aria-unsupported-elements` 88 | - `jsx-a11y/role-has-required-aria-props` 89 | - `jsx-a11y/role-supports-aria-props` 90 | - [breaking] enable react rules: 91 | - `react/jsx-filename-extension` 92 | - `react/jsx-no-comment-textnodes` 93 | - `react/jsx-no-target-blank` 94 | - `react/require-extension` 95 | - `react/no-render-return-value` 96 | - `react/no-find-dom-node` 97 | - `react/no-deprecated` 98 | - [deps] [breaking] update `eslint` to v3, `eslint-config-airbnb-base` to v5, `eslint-find-rules`, `eslint-plugin-import`, `eslint-plugin-jsx-a11y` to v2, `eslint-plugin-react` to v6, `tape`. drop node < 4 support. 99 | - [deps] update `eslint-config-airbnb-base`, `eslint-plugin-react`, `eslint-plugin-import`, `eslint-plugin-jsx-a11y`, `babel-tape-runner`, add `babel-preset-airbnb`. ensure react is `>=` 0.13.0 100 | - [patch] loosen `jsx-pascal-case` rule to allow all caps component names 101 | - [tests] stop testing < node 4 102 | - [tests] use `in-publish` because coffeescript screwed up the prepublish script for everyone 103 | - [tests] Only run `eslint-find-rules` on prepublish, not in tests 104 | - [tests] Even though the base config may not be up to date in the main package, let’s `npm link` the base package into the main one for the sake of travis-ci tests 105 | - [docs] update the peer dep install command to dynamically look up the right version numbers when installing peer deps 106 | - add `safe-publish-latest` to `prepublish` 107 | 108 | 9.0.1 / 2016-05-08 109 | ================== 110 | - [patch] update `eslint-config-airbnb-base` to v3.0.1 111 | 112 | 9.0.0 / 2016-05-07 113 | ================== 114 | - [breaking] update `eslint-config-airbnb-base` to v3 115 | - [deps] update `eslint-find-rules`, `eslint-plugin-import`, `eslint-plugin-jsx-a11y` 116 | 117 | 8.0.0 / 2016-04-21 118 | ================== 119 | - [breaking] Migrate non-React rules to a separate linter config (`eslint-config-airbnb-base`) 120 | - [breaking] disallow empty methods 121 | - [breaking] disallow empty restructuring patterns 122 | - [breaking] enable `no-restricted-syntax` rule 123 | - [breaking] enable `global-require` rule 124 | - [breaking] [react] enable `react/jsx-curly-spacing` rule ([#693](https://github.com/airbnb/javascript/issues/693)) 125 | - [semver-minor] [react] Add `react/jsx-first-prop-new-line` rule 126 | - [semver-minor] [react] enable `jsx-equals-spacing` rule 127 | - [semver-minor] [react] enable `jsx-indent` rule 128 | - [semver-minor] enforce spacing inside single-line blocks 129 | - [semver-minor] enforce `no-underscore-dangle` 130 | - [semver-minor] Enable import/no-unresolved and import/export rules ([#825](https://github.com/airbnb/javascript/issues/825)) 131 | - [semver-patch] Enable `no-useless-concat` rule which `prefer-template` already covers 132 | - [semver-patch] Allow `== null` ([#542](https://github.com/airbnb/javascript/issues/542)) 133 | - [dev deps / peer deps] update `eslint`, `eslint-plugin-react`, `eslint-plugin-import` 134 | - [dev deps / peer deps] update `eslint-plugin-jsx-a11y` and rename rules ([#838](https://github.com/airbnb/javascript/issues/838)) 135 | - [refactor] [react] separate a11y rules to their own file 136 | - [refactor] Add missing disabled rules. 137 | - [tests] Add `eslint-find-rules` to prevent missing rules 138 | 139 | 7.0.0 / 2016-04-11 140 | ================== 141 | - [react] [breaking] Add accessibility rules to the React style guide + `eslint-plugin-a11y` 142 | - [breaking] enable `react/require-render-return` 143 | - [breaking] Add `no-dupe-class-members` rule + section ([#785](https://github.com/airbnb/javascript/issues/785)) 144 | - [breaking] error on debugger statements 145 | - [breaking] add `no-useless-escape` rule 146 | - [breaking] add `no-duplicate-imports` rule 147 | - [semver-minor] enable `jsx-pascal-case` rule 148 | - [deps] update `eslint`, `react` 149 | - [dev deps] update `eslint`, `eslint-plugin-react` 150 | 151 | 6.2.0 / 2016-03-22 152 | ================== 153 | - [new] Allow arrow functions in JSX props 154 | - [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)) 155 | - [dev deps] update `tape`, `eslint`, `eslint-plugin-react` 156 | - [peer deps] update `eslint`, `eslint-plugin-react` 157 | 158 | 6.1.0 / 2016-02-22 159 | ================== 160 | - [new] enable [`react/prefer-stateless-function`][react/prefer-stateless-function] 161 | - [dev deps] update `react-plugin-eslint`, `eslint`, `tape` 162 | 163 | 6.0.2 / 2016-02-22 164 | ================== 165 | - [fix] disable [`no-confusing-arrow`][no-confusing-arrow] due to an `eslint` bug ([#752](https://github.com/airbnb/javascript/issues/752)) 166 | 167 | 6.0.1 / 2016-02-21 168 | ================== 169 | - [fix] disable [`newline-per-chained-call`][newline-per-chained-call] due to an `eslint` bug ([#748](https://github.com/airbnb/javascript/issues/748)) 170 | 171 | 6.0.0 / 2016-02-21 172 | ================== 173 | - [breaking] enable [`array-callback-return`][array-callback-return] 174 | - [breaking] enable [`no-confusing-arrow`][no-confusing-arrow] 175 | - [breaking] enable [`no-new-symbol`][no-new-symbol] 176 | - [breaking] enable [`no-restricted-imports`][no-restricted-imports] 177 | - [breaking] enable [`no-useless-constructor`][no-useless-constructor] 178 | - [breaking] enable [`prefer-rest-params`][prefer-rest-params] 179 | - [breaking] enable [`template-curly-spacing`][template-curly-spacing] 180 | - [breaking] enable [`newline-per-chained-call`][newline-per-chained-call] 181 | - [breaking] enable [`one-var-declaration-per-line`][one-var-declaration-per-line] 182 | - [breaking] enable [`no-self-assign`][no-self-assign] 183 | - [breaking] enable [`no-whitespace-before-property`][no-whitespace-before-property] 184 | - [breaking] [react] enable [`react/jsx-space-before-closing`][react/jsx-space-before-closing] 185 | - [breaking] [react] enable `static-methods` at top of [`react/sort-comp`][react/sort-comp] 186 | - [breaking] [react] don't `ignoreTranspilerName` for [`react/display-name`][react/display-name] 187 | - [peer+dev deps] update `eslint`, `eslint-plugin-react` ([#730](https://github.com/airbnb/javascript/issues/730)) 188 | 189 | 5.0.1 / 2016-02-13 190 | ================== 191 | - [fix] `eslint` peerDep should not include breaking changes 192 | 193 | 5.0.0 / 2016-02-03 194 | ================== 195 | - [breaking] disallow unneeded ternary expressions 196 | - [breaking] Avoid lexical declarations in case/default clauses 197 | - [dev deps] update `babel-tape-runner`, `eslint-plugin-react`, `react`, `tape` 198 | 199 | 4.0.0 / 2016-01-22 200 | ================== 201 | - [breaking] require outer IIFE wrapping; flesh out guide section 202 | - [minor] Add missing [`arrow-body-style`][arrow-body-style], [`prefer-template`][prefer-template] rules ([#678](https://github.com/airbnb/javascript/issues/678)) 203 | - [minor] Add [`prefer-arrow-callback`][prefer-arrow-callback] to ES6 rules (to match the guide) ([#677](https://github.com/airbnb/javascript/issues/677)) 204 | - [Tests] run `npm run lint` as part of tests; fix errors 205 | - [Tests] use `parallelshell` to parallelize npm run-scripts 206 | 207 | 3.1.0 / 2016-01-07 208 | ================== 209 | - [minor] Allow multiple stateless components in a single file 210 | 211 | 3.0.2 / 2016-01-06 212 | ================== 213 | - [fix] Ignore URLs in [`max-len`][max-len] ([#664](https://github.com/airbnb/javascript/issues/664)) 214 | 215 | 3.0.1 / 2016-01-06 216 | ================== 217 | - [fix] because we use babel, keywords should not be quoted 218 | 219 | 3.0.0 / 2016-01-04 220 | ================== 221 | - [breaking] enable [`quote-props`][quote-props] rule ([#632](https://github.com/airbnb/javascript/issues/632)) 222 | - [breaking] Define a max line length of 100 characters ([#639](https://github.com/airbnb/javascript/issues/639)) 223 | - [breaking] [react] Minor cleanup for the React styleguide, add [`react/jsx-no-bind`][react/jsx-no-bind] ([#619](https://github.com/airbnb/javascript/issues/619)) 224 | - [breaking] update best-practices config to prevent parameter object manipulation ([#627](https://github.com/airbnb/javascript/issues/627)) 225 | - [minor] Enable [`react/no-is-mounted`][react/no-is-mounted] rule (#635, #633) 226 | - [minor] Sort [`react/prefer-es6-class`][react/prefer-es6-class] alphabetically ([#634](https://github.com/airbnb/javascript/issues/634)) 227 | - [minor] enable [`react/prefer-es6-class`][react/prefer-es6-class] rule 228 | - Permit strict mode in "legacy" config 229 | - [react] add missing rules from `eslint-plugin-react` (enforcing where necessary) ([#581](https://github.com/airbnb/javascript/issues/581)) 230 | - [dev deps] update `eslint-plugin-react` 231 | 232 | 2.1.1 / 2015-12-15 233 | ================== 234 | - [fix] Remove deprecated [`react/jsx-quotes`][react/jsx-quotes] ([#622](https://github.com/airbnb/javascript/issues/622)) 235 | 236 | 2.1.0 / 2015-12-15 237 | ================== 238 | - [fix] use `require.resolve` to allow nested `extend`s ([#582](https://github.com/airbnb/javascript/issues/582)) 239 | - [new] enable [`object-shorthand`][object-shorthand] rule ([#621](https://github.com/airbnb/javascript/issues/621)) 240 | - [new] enable [`arrow-spacing`][arrow-spacing] rule ([#517](https://github.com/airbnb/javascript/issues/517)) 241 | - [docs] flesh out react rule defaults ([#618](https://github.com/airbnb/javascript/issues/618)) 242 | 243 | 2.0.0 / 2015-12-03 244 | ================== 245 | - [breaking] [`space-before-function-paren`][space-before-function-paren]: require function spacing: `function (` ([#605](https://github.com/airbnb/javascript/issues/605)) 246 | - [breaking] [`indent`][indent]: Fix switch statement indentation rule ([#606](https://github.com/airbnb/javascript/issues/606)) 247 | - [breaking] [`array-bracket-spacing`][array-bracket-spacing], [`computed-property-spacing`][computed-property-spacing]: disallow spacing inside brackets ([#594](https://github.com/airbnb/javascript/issues/594)) 248 | - [breaking] [`object-curly-spacing`][object-curly-spacing]: require padding inside curly braces ([#594](https://github.com/airbnb/javascript/issues/594)) 249 | - [breaking] [`space-in-parens`][space-in-parens]: disallow spaces in parens ([#594](https://github.com/airbnb/javascript/issues/594)) 250 | 251 | 1.0.2 / 2015-11-25 252 | ================== 253 | - [breaking] [`no-multiple-empty-lines`][no-multiple-empty-lines]: only allow 1 blank line at EOF ([#578](https://github.com/airbnb/javascript/issues/578)) 254 | - [new] `restParams`: enable rest params ([#592](https://github.com/airbnb/javascript/issues/592)) 255 | 256 | 1.0.1 / 2015-11-25 257 | ================== 258 | - *erroneous publish* 259 | 260 | 1.0.0 / 2015-11-08 261 | ================== 262 | - require `eslint` `v1.0.0` or higher 263 | - remove `babel-eslint` dependency 264 | 265 | 0.1.1 / 2015-11-05 266 | ================== 267 | - remove [`id-length`][id-length] rule ([#569](https://github.com/airbnb/javascript/issues/569)) 268 | - enable [`no-mixed-spaces-and-tabs`][no-mixed-spaces-and-tabs] ([#539](https://github.com/airbnb/javascript/issues/539)) 269 | - enable [`no-const-assign`][no-const-assign] ([#560](https://github.com/airbnb/javascript/issues/560)) 270 | - enable [`space-before-keywords`][space-before-keywords] ([#554](https://github.com/airbnb/javascript/issues/554)) 271 | 272 | 0.1.0 / 2015-11-05 273 | ================== 274 | - switch to modular rules files courtesy the [eslint-config-default][ecd] project and [@taion][taion]. [PR][pr-modular] 275 | - export `eslint-config-airbnb/legacy` for ES5-only users. `eslint-config-airbnb/legacy` does not require the `babel-eslint` parser. [PR][pr-legacy] 276 | 277 | 0.0.9 / 2015-09-24 278 | ================== 279 | - add rule [`no-undef`][no-undef] 280 | - add rule [`id-length`][id-length] 281 | 282 | 0.0.8 / 2015-08-21 283 | ================== 284 | - now has a changelog 285 | - now is modular (see instructions above for with react and without react versions) 286 | 287 | 0.0.7 / 2015-07-30 288 | ================== 289 | - TODO: fill in 290 | 291 | 292 | [ecd]: https://github.com/walmartlabs/eslint-config-defaults 293 | [taion]: https://github.com/taion 294 | [pr-modular]: https://github.com/airbnb/javascript/pull/526 295 | [pr-legacy]: https://github.com/airbnb/javascript/pull/527 296 | 297 | [array-bracket-spacing]: http://eslint.org/docs/rules/array-bracket-spacing 298 | [array-callback-return]: http://eslint.org/docs/rules/array-callback-return 299 | [arrow-body-style]: http://eslint.org/docs/rules/arrow-body-style 300 | [arrow-spacing]: http://eslint.org/docs/rules/arrow-spacing 301 | [computed-property-spacing]: http://eslint.org/docs/rules/computed-property-spacing 302 | [id-length]: http://eslint.org/docs/rules/id-length 303 | [indent]: http://eslint.org/docs/rules/indent 304 | [max-len]: http://eslint.org/docs/rules/max-len 305 | [newline-per-chained-call]: http://eslint.org/docs/rules/newline-per-chained-call 306 | [no-confusing-arrow]: http://eslint.org/docs/rules/no-confusing-arrow 307 | [no-const-assign]: http://eslint.org/docs/rules/no-const-assign 308 | [no-mixed-spaces-and-tabs]: http://eslint.org/docs/rules/no-mixed-spaces-and-tabs 309 | [no-multiple-empty-lines]: http://eslint.org/docs/rules/no-multiple-empty-lines 310 | [no-new-symbol]: http://eslint.org/docs/rules/no-new-symbol 311 | [no-restricted-imports]: http://eslint.org/docs/rules/no-restricted-imports 312 | [no-self-assign]: http://eslint.org/docs/rules/no-self-assign 313 | [no-undef]: http://eslint.org/docs/rules/no-undef 314 | [no-useless-constructor]: http://eslint.org/docs/rules/no-useless-constructor 315 | [no-whitespace-before-property]: http://eslint.org/docs/rules/no-whitespace-before-property 316 | [object-curly-spacing]: http://eslint.org/docs/rules/object-curly-spacing 317 | [object-shorthand]: http://eslint.org/docs/rules/object-shorthand 318 | [one-var-declaration-per-line]: http://eslint.org/docs/rules/one-var-declaration-per-line 319 | [prefer-arrow-callback]: http://eslint.org/docs/rules/prefer-arrow-callback 320 | [prefer-rest-params]: http://eslint.org/docs/rules/prefer-rest-params 321 | [prefer-template]: http://eslint.org/docs/rules/prefer-template 322 | [quote-props]: http://eslint.org/docs/rules/quote-props 323 | [space-before-function-paren]: http://eslint.org/docs/rules/space-before-function-paren 324 | [space-before-keywords]: http://eslint.org/docs/rules/space-before-keywords 325 | [space-in-parens]: http://eslint.org/docs/rules/space-in-parens 326 | [template-curly-spacing]: http://eslint.org/docs/rules/template-curly-spacing 327 | 328 | [react/jsx-space-before-closing]: https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-space-before-closing.md 329 | [react/sort-comp]: https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/sort-comp.md 330 | [react/display-name]: https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/display-name.md 331 | [react/jsx-no-bind]: https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-bind.md 332 | [react/no-is-mounted]: https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-is-mounted.md 333 | [react/prefer-es6-class]: https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/prefer-es6-class.md 334 | [react/jsx-quotes]: https://github.com/yannickcr/eslint-plugin-react/blob/f817e37beddddc84b4788969f07c524fa7f0823b/docs/rules/jsx-quotes.md 335 | [react/prefer-stateless-function]: https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/prefer-stateless-function.md 336 | -------------------------------------------------------------------------------- /packages/eslint-config-airbnb/README.md: -------------------------------------------------------------------------------- 1 | # eslint-config-airbnb 2 | 3 | [![npm version](https://badge.fury.io/js/eslint-config-airbnb.svg)](http://badge.fury.io/js/eslint-config-airbnb) 4 | 5 | This package provides Airbnb's .eslintrc as an extensible shared config. 6 | 7 | ## Usage 8 | 9 | We export three ESLint configurations for your usage. 10 | 11 | ### eslint-config-airbnb 12 | 13 | Our default export contains all of our ESLint rules, including ECMAScript 6+ and React. It requires `eslint`, `eslint-plugin-import`, `eslint-plugin-react`, and `eslint-plugin-jsx-a11y`. If you don't need React, see [eslint-config-airbnb-base](https://npmjs.com/eslint-config-airbnb-base). 14 | 15 | If you use yarn, run `yarn add --dev eslint-config-airbnb-base eslint-plugin-import eslint-plugin-react eslint-plugin-jsx-a11y`, and see below for npm instructions. 16 | 17 | 1. Install the correct versions of each package, which are listed by the command: 18 | 19 | ```sh 20 | npm info "eslint-config-airbnb@latest" peerDependencies 21 | ``` 22 | 23 | Linux/OSX users can run 24 | 25 | ```sh 26 | ( 27 | export PKG=eslint-config-airbnb; 28 | npm info "$PKG@latest" peerDependencies --json | command sed 's/[\{\},]//g ; s/: /@/g' | xargs npm install --save-dev "$PKG@latest" 29 | ) 30 | ``` 31 | 32 | Which produces and runs a command like: 33 | 34 | ```sh 35 | npm install --save-dev eslint-config-airbnb eslint@^#.#.# eslint-plugin-jsx-a11y@^#.#.# eslint-plugin-import@^#.#.# eslint-plugin-react@^#.#.# 36 | ``` 37 | 38 | Windows users can either install all the peer dependencies manually, or use the [install-peerdeps](https://github.com/nathanhleung/install-peerdeps) cli tool. 39 | 40 | ```sh 41 | npm install -g install-peerdeps 42 | install-peerdeps --dev eslint-config-airbnb 43 | ``` 44 | 45 | The cli will produce and run a command like: 46 | 47 | ```sh 48 | npm install --save-dev eslint-config-airbnb eslint@^#.#.# eslint-plugin-jsx-a11y@^#.#.# eslint-plugin-import@^#.#.# eslint-plugin-react@^#.#.# 49 | ``` 50 | 51 | 2. Add `"extends": "airbnb"` to your .eslintrc 52 | 53 | ### eslint-config-airbnb/base 54 | 55 | This entry point is deprecated. See [eslint-config-airbnb-base](https://npmjs.com/eslint-config-airbnb-base). 56 | 57 | ### eslint-config-airbnb/legacy 58 | 59 | This entry point is deprecated. See [eslint-config-airbnb-base](https://npmjs.com/eslint-config-airbnb-base). 60 | 61 | See [Airbnb's Javascript styleguide](https://github.com/airbnb/javascript) and 62 | the [ESlint config docs](http://eslint.org/docs/user-guide/configuring#extending-configuration-files) 63 | for more information. 64 | 65 | ## Improving this config 66 | 67 | Consider adding test cases if you're making complicated rules changes, like anything involving regexes. Perhaps in a distant future, we could use literate programming to structure our README as test cases for our .eslintrc? 68 | 69 | You can run tests with `npm test`. 70 | 71 | You can make sure this module lints with itself using `npm run lint`. 72 | -------------------------------------------------------------------------------- /packages/eslint-config-airbnb/base.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ['eslint-config-airbnb-base'].map(require.resolve), 3 | rules: {}, 4 | }; 5 | -------------------------------------------------------------------------------- /packages/eslint-config-airbnb/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: [ 3 | 'eslint-config-airbnb-base', 4 | 'eslint-config-airbnb-base/rules/strict', 5 | './rules/react', 6 | './rules/react-a11y', 7 | ].map(require.resolve), 8 | rules: {} 9 | }; 10 | -------------------------------------------------------------------------------- /packages/eslint-config-airbnb/legacy.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ['eslint-config-airbnb-base/legacy'].map(require.resolve), 3 | rules: {}, 4 | }; 5 | -------------------------------------------------------------------------------- /packages/eslint-config-airbnb/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "eslint-config-airbnb", 3 | "version": "15.1.0", 4 | "description": "Airbnb's ESLint config, following our styleguide", 5 | "main": "index.js", 6 | "scripts": { 7 | "prelint": "editorconfig-tools check * rules/* test/*", 8 | "lint": "eslint .", 9 | "tests-only": "babel-tape-runner ./test/test-*.js", 10 | "prepublish": "(in-install || eslint-find-rules --unused) && (not-in-publish || npm test) && safe-publish-latest", 11 | "pretest": "npm run --silent lint", 12 | "test": "npm run --silent tests-only", 13 | "pretravis": "cd ../eslint-config-airbnb-base && npm install && npm link && cd - && npm link --no-save eslint-config-airbnb-base", 14 | "travis": "npm run --silent test", 15 | "posttravis": "npm unlink eslint-config-airbnb-base >/dev/null &" 16 | }, 17 | "repository": { 18 | "type": "git", 19 | "url": "https://github.com/airbnb/javascript" 20 | }, 21 | "keywords": [ 22 | "eslint", 23 | "eslintconfig", 24 | "config", 25 | "airbnb", 26 | "javascript", 27 | "styleguide" 28 | ], 29 | "author": "Jake Teton-Landis (https://twitter.com/@jitl)", 30 | "contributors": [ 31 | { 32 | "name": "Jake Teton-Landis", 33 | "url": "https://twitter.com/jitl" 34 | }, 35 | { 36 | "name": "Jordan Harband", 37 | "email": "ljharb@gmail.com", 38 | "url": "http://ljharb.codes" 39 | }, 40 | { 41 | "name": "Harrison Shoff", 42 | "url": "https://twitter.com/hshoff" 43 | } 44 | ], 45 | "license": "MIT", 46 | "bugs": { 47 | "url": "https://github.com/airbnb/javascript/issues" 48 | }, 49 | "homepage": "https://github.com/airbnb/javascript", 50 | "dependencies": { 51 | "eslint-config-airbnb-base": "^11.3.0" 52 | }, 53 | "devDependencies": { 54 | "babel-preset-airbnb": "^2.4.0", 55 | "babel-tape-runner": "^2.0.1", 56 | "editorconfig-tools": "^0.1.1", 57 | "eslint": "^3.19.0 || ^4.3.0", 58 | "eslint-find-rules": "^3.1.1", 59 | "eslint-plugin-import": "^2.7.0", 60 | "eslint-plugin-jsx-a11y": "^5.1.1", 61 | "eslint-plugin-react": "^7.1.0", 62 | "in-publish": "^2.0.0", 63 | "react": ">= 0.13.0", 64 | "safe-publish-latest": "^1.1.1", 65 | "tape": "^4.7.0" 66 | }, 67 | "peerDependencies": { 68 | "eslint": "^3.19.0 || ^4.3.0", 69 | "eslint-plugin-jsx-a11y": "^5.1.1", 70 | "eslint-plugin-import": "^2.7.0", 71 | "eslint-plugin-react": "^7.1.0" 72 | }, 73 | "engines": { 74 | "node": ">= 4" 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /packages/eslint-config-airbnb/rules/react-a11y.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: [ 3 | 'jsx-a11y', 4 | 'react' 5 | ], 6 | 7 | parserOptions: { 8 | ecmaFeatures: { 9 | jsx: true, 10 | }, 11 | }, 12 | 13 | rules: { 14 | // Enforce that anchors have content 15 | // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/anchor-has-content.md 16 | 'jsx-a11y/anchor-has-content': ['error', { components: [''] }], 17 | 18 | // Require ARIA roles to be valid and non-abstract 19 | // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/aria-role.md 20 | 'jsx-a11y/aria-role': ['error', { ignoreNonDom: false }], 21 | 22 | // Enforce all aria-* props are valid. 23 | // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/aria-props.md 24 | 'jsx-a11y/aria-props': 'error', 25 | 26 | // Enforce ARIA state and property values are valid. 27 | // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/aria-proptypes.md 28 | 'jsx-a11y/aria-proptypes': 'error', 29 | 30 | // Enforce that elements that do not support ARIA roles, states, and 31 | // properties do not have those attributes. 32 | // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/aria-unsupported-elements.md 33 | 'jsx-a11y/aria-unsupported-elements': 'error', 34 | 35 | // disallow href "#" 36 | // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/href-no-hash.md 37 | 'jsx-a11y/href-no-hash': ['error', { components: ['a'] }], 38 | 39 | // Enforce that all elements that require alternative text have meaningful information 40 | // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/alt-text.md 41 | 'jsx-a11y/alt-text': ['error', { 42 | elements: ['img', 'object', 'area', 'input[type="image"]'], 43 | img: [], 44 | object: [], 45 | area: [], 46 | 'input[type="image"]': [], 47 | }], 48 | 49 | // Prevent img alt text from containing redundant words like "image", "picture", or "photo" 50 | // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/img-redundant-alt.md 51 | 'jsx-a11y/img-redundant-alt': 'error', 52 | 53 | // require that JSX labels use "htmlFor" 54 | // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/label-has-for.md 55 | 'jsx-a11y/label-has-for': ['error', { components: ['label'] }], 56 | 57 | // require that mouseover/out come with focus/blur, for keyboard-only users 58 | // TODO: evaluate 59 | // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/mouse-events-have-key-events.md 60 | 'jsx-a11y/mouse-events-have-key-events': 'off', 61 | 62 | // Prevent use of `accessKey` 63 | // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/no-access-key.md 64 | 'jsx-a11y/no-access-key': 'error', 65 | 66 | // require onBlur instead of onChange 67 | // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/no-onchange.md 68 | 'jsx-a11y/no-onchange': 'off', 69 | 70 | // Elements with an interactive role and interaction handlers must be focusable 71 | // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/interactive-supports-focus.md 72 | 'jsx-a11y/interactive-supports-focus': 'error', 73 | 74 | // Enforce that elements with ARIA roles must have all required attributes 75 | // for that role. 76 | // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/role-has-required-aria-props.md 77 | 'jsx-a11y/role-has-required-aria-props': 'error', 78 | 79 | // Enforce that elements with explicit or implicit roles defined contain 80 | // only aria-* properties supported by that role. 81 | // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/role-supports-aria-props.md 82 | 'jsx-a11y/role-supports-aria-props': 'error', 83 | 84 | // Enforce tabIndex value is not greater than zero. 85 | // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/tabindex-no-positive.md 86 | 'jsx-a11y/tabindex-no-positive': 'error', 87 | 88 | // ensure tags have content and are not aria-hidden 89 | // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/heading-has-content.md 90 | 'jsx-a11y/heading-has-content': ['error', { components: [''] }], 91 | 92 | // require HTML elements to have a "lang" prop 93 | // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/html-has-lang.md 94 | 'jsx-a11y/html-has-lang': 'error', 95 | 96 | // require HTML element's lang prop to be valid 97 | // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/lang.md 98 | 'jsx-a11y/lang': 'error', 99 | 100 | // prevent distracting elements, like and 101 | // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/no-distracting-elements.md 102 | 'jsx-a11y/no-distracting-elements': ['error', { 103 | elements: ['marquee', 'blink'], 104 | }], 105 | 106 | // only allow to have the "scope" attr 107 | // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/scope.md 108 | 'jsx-a11y/scope': 'error', 109 | 110 | // require onClick be accompanied by onKeyUp/onKeyDown/onKeyPress 111 | // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/click-events-have-key-events.md 112 | // TODO: enable? 113 | 'jsx-a11y/click-events-have-key-events': 'off', 114 | 115 | // Enforce that DOM elements without semantic behavior not have interaction handlers 116 | // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/no-static-element-interactions.md 117 | 'jsx-a11y/no-static-element-interactions': ['error', { 118 | handlers: [ 119 | 'onClick', 120 | 'onMouseDown', 121 | 'onMouseUp', 122 | 'onKeyPress', 123 | 'onKeyDown', 124 | 'onKeyUp', 125 | ] 126 | }], 127 | 128 | // A non-interactive element does not support event handlers (mouse and key handlers) 129 | // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/no-noninteractive-element-interactions.md 130 | 'jsx-a11y/no-noninteractive-element-interactions': ['error', { 131 | handlers: [ 132 | 'onClick', 133 | 'onMouseDown', 134 | 'onMouseUp', 135 | 'onKeyPress', 136 | 'onKeyDown', 137 | 'onKeyUp', 138 | ] 139 | }], 140 | 141 | // ensure emoji are accessible 142 | // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/accessible-emoji.md 143 | 'jsx-a11y/accessible-emoji': 'error', 144 | 145 | // elements with aria-activedescendant must be tabbable 146 | // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/aria-activedescendant-has-tabindex.md 147 | 'jsx-a11y/aria-activedescendant-has-tabindex': 'error', 148 | 149 | // ensure iframe elements have a unique title 150 | // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/iframe-has-title.md 151 | 'jsx-a11y/iframe-has-title': 'error', 152 | 153 | // prohibit autoFocus prop 154 | // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/no-autofocus.md 155 | 'jsx-a11y/no-autofocus': ['error', { ignoreNonDOM: true }], 156 | 157 | // ensure HTML elements do not specify redundant ARIA roles 158 | // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/no-redundant-roles.md 159 | 'jsx-a11y/no-redundant-roles': 'error', 160 | 161 | // media elements must have captions 162 | // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/media-has-caption.md 163 | 'jsx-a11y/media-has-caption': ['error', { 164 | audio: [], 165 | video: [], 166 | track: [], 167 | }], 168 | 169 | // WAI-ARIA roles should not be used to convert an interactive element to non-interactive 170 | // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/no-interactive-element-to-noninteractive-role.md 171 | 'jsx-a11y/no-interactive-element-to-noninteractive-role': ['error', { 172 | tr: ['none', 'presentation'], 173 | }], 174 | 175 | // WAI-ARIA roles should not be used to convert a non-interactive element to interactive 176 | // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/no-noninteractive-element-to-interactive-role.md 177 | 'jsx-a11y/no-noninteractive-element-to-interactive-role': ['error', { 178 | ul: ['listbox', 'menu', 'menubar', 'radiogroup', 'tablist', 'tree', 'treegrid'], 179 | ol: ['listbox', 'menu', 'menubar', 'radiogroup', 'tablist', 'tree', 'treegrid'], 180 | li: ['menuitem', 'option', 'row', 'tab', 'treeitem'], 181 | table: ['grid'], 182 | td: ['gridcell'], 183 | }], 184 | 185 | // Tab key navigation should be limited to elements on the page that can be interacted with. 186 | // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/no-noninteractive-tabindex.md 187 | 'jsx-a11y/no-noninteractive-tabindex': ['error', { 188 | tags: [], 189 | roles: ['tabpanel'], 190 | }], 191 | 192 | // ensure tags are valid 193 | // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/0745af376cdc8686d85a361ce36952b1fb1ccf6e/docs/rules/anchor-is-valid.md 194 | // TODO: enable, semver-major 195 | 'jsx-a11y/anchor-is-valid': ['off', { 196 | components: ['Link'], 197 | specialLink: [], 198 | aspects: ['noHref', 'invalidHref', 'preferButton'], 199 | }], 200 | }, 201 | }; 202 | -------------------------------------------------------------------------------- /packages/eslint-config-airbnb/rules/react.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: [ 3 | 'react', 4 | ], 5 | 6 | parserOptions: { 7 | ecmaFeatures: { 8 | jsx: true, 9 | }, 10 | }, 11 | 12 | // View link below for react rules documentation 13 | // https://github.com/yannickcr/eslint-plugin-react#list-of-supported-rules 14 | rules: { 15 | // Specify whether double or single quotes should be used in JSX attributes 16 | // http://eslint.org/docs/rules/jsx-quotes 17 | 'jsx-quotes': ['error', 'prefer-double'], 18 | 19 | 'class-methods-use-this': ['error', { 20 | exceptMethods: [ 21 | 'render', 22 | 'getInitialState', 23 | 'getDefaultProps', 24 | 'getChildContext', 25 | 'componentWillMount', 26 | 'componentDidMount', 27 | 'componentWillReceiveProps', 28 | 'shouldComponentUpdate', 29 | 'componentWillUpdate', 30 | 'componentDidUpdate', 31 | 'componentWillUnmount', 32 | ], 33 | }], 34 | 35 | // Prevent missing displayName in a React component definition 36 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/display-name.md 37 | 'react/display-name': ['off', { ignoreTranspilerName: false }], 38 | 39 | // Forbid certain propTypes (any, array, object) 40 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/forbid-prop-types.md 41 | 'react/forbid-prop-types': ['error', { forbid: ['any', 'array', 'object'] }], 42 | 43 | // Enforce boolean attributes notation in JSX 44 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-boolean-value.md 45 | 'react/jsx-boolean-value': ['error', 'never'], 46 | 47 | // Validate closing bracket location in JSX 48 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-closing-bracket-location.md 49 | 'react/jsx-closing-bracket-location': ['error', 'line-aligned'], 50 | 51 | // Validate closing tag location in JSX 52 | // https://github.com/yannickcr/eslint-plugin-react/blob/9e13ae2c51e44872b45cc15bf1ac3a72105bdd0e/docs/rules/jsx-closing-tag-location.md 53 | // TODO: enable, semver-minor 54 | 'react/jsx-closing-tag-location': 'off', 55 | 56 | // Enforce or disallow spaces inside of curly braces in JSX attributes 57 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-curly-spacing.md 58 | 'react/jsx-curly-spacing': ['error', 'never', { allowMultiline: true }], 59 | 60 | // Enforce event handler naming conventions in JSX 61 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-handler-names.md 62 | 'react/jsx-handler-names': ['off', { 63 | eventHandlerPrefix: 'handle', 64 | eventHandlerPropPrefix: 'on', 65 | }], 66 | 67 | // Validate props indentation in JSX 68 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-indent-props.md 69 | 'react/jsx-indent-props': ['error', 2], 70 | 71 | // Validate JSX has key prop when in array or iterator 72 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-key.md 73 | 'react/jsx-key': 'off', 74 | 75 | // Limit maximum of props on a single line in JSX 76 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-max-props-per-line.md 77 | 'react/jsx-max-props-per-line': ['error', { maximum: 1, when: 'multiline' }], 78 | 79 | // Prevent usage of .bind() in JSX props 80 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-bind.md 81 | 'react/jsx-no-bind': ['error', { 82 | ignoreRefs: true, 83 | allowArrowFunctions: true, 84 | allowBind: false, 85 | }], 86 | 87 | // Prevent duplicate props in JSX 88 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-duplicate-props.md 89 | 'react/jsx-no-duplicate-props': ['error', { ignoreCase: true }], 90 | 91 | // Prevent usage of unwrapped JSX strings 92 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-literals.md 93 | 'react/jsx-no-literals': 'off', 94 | 95 | // Disallow undeclared variables in JSX 96 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-undef.md 97 | 'react/jsx-no-undef': 'error', 98 | 99 | // Enforce PascalCase for user-defined JSX components 100 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-pascal-case.md 101 | 'react/jsx-pascal-case': ['error', { 102 | allowAllCaps: true, 103 | ignore: [], 104 | }], 105 | 106 | // Enforce propTypes declarations alphabetical sorting 107 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/sort-prop-types.md 108 | 'react/sort-prop-types': ['off', { 109 | ignoreCase: true, 110 | callbacksLast: false, 111 | requiredFirst: false, 112 | }], 113 | 114 | // Deprecated in favor of react/jsx-sort-props 115 | 'react/jsx-sort-prop-types': 'off', 116 | 117 | // Enforce props alphabetical sorting 118 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-sort-props.md 119 | 'react/jsx-sort-props': ['off', { 120 | ignoreCase: true, 121 | callbacksLast: false, 122 | shorthandFirst: false, 123 | shorthandLast: false, 124 | noSortAlphabetically: false, 125 | reservedFirst: true, 126 | }], 127 | 128 | // Prevent React to be incorrectly marked as unused 129 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-uses-react.md 130 | 'react/jsx-uses-react': ['error'], 131 | 132 | // Prevent variables used in JSX to be incorrectly marked as unused 133 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-uses-vars.md 134 | 'react/jsx-uses-vars': 'error', 135 | 136 | // Prevent usage of dangerous JSX properties 137 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-danger.md 138 | 'react/no-danger': 'warn', 139 | 140 | // Prevent usage of deprecated methods 141 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-deprecated.md 142 | 'react/no-deprecated': ['error'], 143 | 144 | // Prevent usage of setState in componentDidMount 145 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-did-mount-set-state.md 146 | 'react/no-did-mount-set-state': 'error', 147 | 148 | // Prevent usage of setState in componentDidUpdate 149 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-did-update-set-state.md 150 | 'react/no-did-update-set-state': 'error', 151 | 152 | // Prevent usage of setState in componentWillUpdate 153 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-will-update-set-state.md 154 | 'react/no-will-update-set-state': 'error', 155 | 156 | // Prevent direct mutation of this.state 157 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-direct-mutation-state.md 158 | 'react/no-direct-mutation-state': 'off', 159 | 160 | // Prevent usage of isMounted 161 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-is-mounted.md 162 | 'react/no-is-mounted': 'error', 163 | 164 | // Prevent multiple component definition per file 165 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-multi-comp.md 166 | 'react/no-multi-comp': ['error', { ignoreStateless: true }], 167 | 168 | // Prevent usage of setState 169 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-set-state.md 170 | 'react/no-set-state': 'off', 171 | 172 | // Prevent using string references 173 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-string-refs.md 174 | 'react/no-string-refs': 'error', 175 | 176 | // Prevent usage of unknown DOM property 177 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-unknown-property.md 178 | 'react/no-unknown-property': 'error', 179 | 180 | // Require ES6 class declarations over React.createClass 181 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/prefer-es6-class.md 182 | 'react/prefer-es6-class': ['error', 'always'], 183 | 184 | // Require stateless functions when not using lifecycle methods, setState or ref 185 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/prefer-stateless-function.md 186 | 'react/prefer-stateless-function': ['error', { ignorePureComponents: true }], 187 | 188 | // Prevent missing props validation in a React component definition 189 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/prop-types.md 190 | 'react/prop-types': ['error', { ignore: [], customValidators: [], skipUndeclared: false }], 191 | 192 | // Prevent missing React when using JSX 193 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/react-in-jsx-scope.md 194 | 'react/react-in-jsx-scope': 'error', 195 | 196 | // Require render() methods to return something 197 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/require-render-return.md 198 | 'react/require-render-return': 'error', 199 | 200 | // Prevent extra closing tags for components without children 201 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/self-closing-comp.md 202 | 'react/self-closing-comp': 'error', 203 | 204 | // Enforce component methods order 205 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/sort-comp.md 206 | 'react/sort-comp': ['error', { 207 | order: [ 208 | 'static-methods', 209 | 'lifecycle', 210 | '/^on.+$/', 211 | '/^(get|set)(?!(InitialState$|DefaultProps$|ChildContext$)).+$/', 212 | 'everything-else', 213 | '/^render.+$/', 214 | 'render' 215 | ], 216 | }], 217 | 218 | // Prevent missing parentheses around multilines JSX 219 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-wrap-multilines.md 220 | 'react/jsx-wrap-multilines': ['error', { 221 | declaration: true, 222 | assignment: true, 223 | return: true, 224 | arrow: true, 225 | }], 226 | 227 | // Require that the first prop in a JSX element be on a new line when the element is multiline 228 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-first-prop-new-line.md 229 | 'react/jsx-first-prop-new-line': ['error', 'multiline-multiprop'], 230 | 231 | // Enforce spacing around jsx equals signs 232 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-equals-spacing.md 233 | 'react/jsx-equals-spacing': ['error', 'never'], 234 | 235 | // Enforce JSX indentation 236 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-indent.md 237 | 'react/jsx-indent': ['error', 2], 238 | 239 | // Disallow target="_blank" on links 240 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-target-blank.md 241 | 'react/jsx-no-target-blank': 'error', 242 | 243 | // only .jsx files may have JSX 244 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-filename-extension.md 245 | 'react/jsx-filename-extension': ['error', { extensions: ['.jsx'] }], 246 | 247 | // prevent accidental JS comments from being injected into JSX as text 248 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-comment-textnodes.md 249 | 'react/jsx-no-comment-textnodes': 'error', 250 | 251 | // disallow using React.render/ReactDOM.render's return value 252 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-render-return-value.md 253 | 'react/no-render-return-value': 'error', 254 | 255 | // require a shouldComponentUpdate method, or PureRenderMixin 256 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/require-optimization.md 257 | 'react/require-optimization': ['off', { allowDecorators: [] }], 258 | 259 | // warn against using findDOMNode() 260 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-find-dom-node.md 261 | 'react/no-find-dom-node': 'error', 262 | 263 | // Forbid certain props on Components 264 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/forbid-component-props.md 265 | 'react/forbid-component-props': ['off', { forbid: [] }], 266 | 267 | // Forbid certain elements 268 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/forbid-elements.md 269 | 'react/forbid-elements': ['off', { forbid: [], }], 270 | 271 | // Prevent problem with children and props.dangerouslySetInnerHTML 272 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-danger-with-children.md 273 | 'react/no-danger-with-children': 'error', 274 | 275 | // Prevent unused propType definitions 276 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-unused-prop-types.md 277 | 'react/no-unused-prop-types': ['error', { 278 | customValidators: [ 279 | ], 280 | skipShapeProps: true, 281 | }], 282 | 283 | // Require style prop value be an object or var 284 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/style-prop-object.md 285 | 'react/style-prop-object': 'error', 286 | 287 | // Prevent invalid characters from appearing in markup 288 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-unescaped-entities.md 289 | 'react/no-unescaped-entities': 'error', 290 | 291 | // Prevent passing of children as props 292 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-children-prop.md 293 | 'react/no-children-prop': 'error', 294 | 295 | // Validate whitespace in and around the JSX opening and closing brackets 296 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-tag-spacing.md 297 | 'react/jsx-tag-spacing': ['error', { 298 | closingSlash: 'never', 299 | beforeSelfClosing: 'always', 300 | afterOpening: 'never' 301 | }], 302 | 303 | // Enforce spaces before the closing bracket of self-closing JSX elements 304 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-space-before-closing.md 305 | // Deprecated in favor of jsx-tag-spacing 306 | 'react/jsx-space-before-closing': ['off', 'always'], 307 | 308 | // Prevent usage of Array index in keys 309 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-array-index-key.md 310 | 'react/no-array-index-key': 'error', 311 | 312 | // Enforce a defaultProps definition for every prop that is not a required prop 313 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/require-default-props.md 314 | 'react/require-default-props': 'error', 315 | 316 | // Forbids using non-exported propTypes 317 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/forbid-foreign-prop-types.md 318 | 'react/forbid-foreign-prop-types': 'off', 319 | 320 | // Prevent void DOM elements from receiving children 321 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/void-dom-elements-no-children.md 322 | 'react/void-dom-elements-no-children': 'error', 323 | 324 | // Enforce all defaultProps have a corresponding non-required PropType 325 | // https://github.com/yannickcr/eslint-plugin-react/blob/9e13ae2c51e44872b45cc15bf1ac3a72105bdd0e/docs/rules/default-props-match-prop-types.md 326 | // TODO: enable, semver-minor 327 | 'react/default-props-match-prop-types': ['off', { allowRequiredDefaults: false }], 328 | 329 | // Prevent usage of shouldComponentUpdate when extending React.PureComponent 330 | // https://github.com/yannickcr/eslint-plugin-react/blob/9e13ae2c51e44872b45cc15bf1ac3a72105bdd0e/docs/rules/no-redundant-should-component-update.md 331 | // TODO: enable, semver-major 332 | 'react/no-redundant-should-component-update': 'off', 333 | }, 334 | 335 | settings: { 336 | 'import/resolver': { 337 | node: { 338 | extensions: ['.js', '.jsx', '.json'] 339 | } 340 | }, 341 | react: { 342 | pragma: 'React', 343 | version: '15.0' 344 | }, 345 | } 346 | }; 347 | -------------------------------------------------------------------------------- /packages/eslint-config-airbnb/test/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | // disabled because I find it tedious to write tests while following this rule 4 | "no-shadow": 0, 5 | 6 | // tests uses `t` for tape 7 | "id-length": [2, {"min": 2, "properties": "never", "exceptions": ["t"]}] 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /packages/eslint-config-airbnb/test/test-base.js: -------------------------------------------------------------------------------- 1 | import fs from 'fs'; 2 | import path from 'path'; 3 | import test from 'tape'; 4 | 5 | const base = require('../base'); 6 | 7 | const files = { base }; 8 | 9 | fs.readdirSync(path.join(__dirname, '../rules')).forEach((name) => { 10 | if (name === 'react.js' || name === 'react-a11y.js') { 11 | return; 12 | } 13 | 14 | // eslint-disable-next-line import/no-dynamic-require 15 | files[name] = require(`../rules/${name}`); // eslint-disable-line global-require 16 | }); 17 | 18 | Object.keys(files).forEach((name) => { 19 | const config = files[name]; 20 | 21 | test(`${name}: does not reference react`, (t) => { 22 | t.plan(2); 23 | 24 | // scan plugins for react and fail if it is found 25 | const hasReactPlugin = Object.prototype.hasOwnProperty.call(config, 'plugins') && 26 | config.plugins.indexOf('react') !== -1; 27 | t.notOk(hasReactPlugin, 'there is no react plugin'); 28 | 29 | // scan rules for react/ and fail if any exist 30 | const reactRuleIds = Object.keys(config.rules) 31 | .filter(ruleId => ruleId.indexOf('react/') === 0); 32 | t.deepEquals(reactRuleIds, [], 'there are no react/ rules'); 33 | }); 34 | }); 35 | -------------------------------------------------------------------------------- /packages/eslint-config-airbnb/test/test-react-order.js: -------------------------------------------------------------------------------- 1 | import test from 'tape'; 2 | import { CLIEngine } from 'eslint'; 3 | import eslintrc from '../'; 4 | import reactRules from '../rules/react'; 5 | import reactA11yRules from '../rules/react-a11y'; 6 | 7 | const cli = new CLIEngine({ 8 | useEslintrc: false, 9 | baseConfig: eslintrc, 10 | 11 | rules: { 12 | // It is okay to import devDependencies in tests. 13 | 'import/no-extraneous-dependencies': [2, { devDependencies: true }], 14 | }, 15 | }); 16 | 17 | function lint(text) { 18 | // @see http://eslint.org/docs/developer-guide/nodejs-api.html#executeonfiles 19 | // @see http://eslint.org/docs/developer-guide/nodejs-api.html#executeontext 20 | const linter = cli.executeOnText(text); 21 | return linter.results[0]; 22 | } 23 | 24 | function wrapComponent(body) { 25 | return ` 26 | import React from 'react'; 27 | 28 | export default class MyComponent extends React.Component { 29 | /* eslint no-empty-function: 0, class-methods-use-this: 0 */ 30 | ${body} 31 | } 32 | `; 33 | } 34 | 35 | test('validate react prop order', (t) => { 36 | t.test('make sure our eslintrc has React and JSX linting dependencies', (t) => { 37 | t.plan(2); 38 | t.deepEqual(reactRules.plugins, ['react']); 39 | t.deepEqual(reactA11yRules.plugins, ['jsx-a11y', 'react']); 40 | }); 41 | 42 | t.test('passes a good component', (t) => { 43 | t.plan(3); 44 | const result = lint(wrapComponent(` 45 | componentWillMount() {} 46 | componentDidMount() {} 47 | setFoo() {} 48 | getFoo() {} 49 | setBar() {} 50 | someMethod() {} 51 | renderDogs() {} 52 | render() { return
; }`)); 53 | 54 | t.notOk(result.warningCount, 'no warnings'); 55 | t.notOk(result.errorCount, 'no errors'); 56 | t.deepEquals(result.messages, [], 'no messages in results'); 57 | }); 58 | 59 | t.test('order: when random method is first', (t) => { 60 | t.plan(2); 61 | const result = lint(wrapComponent(` 62 | someMethod() {} 63 | componentWillMount() {} 64 | componentDidMount() {} 65 | setFoo() {} 66 | getFoo() {} 67 | setBar() {} 68 | renderDogs() {} 69 | render() { return
; } 70 | `)); 71 | 72 | t.ok(result.errorCount, 'fails'); 73 | t.equal(result.messages[0].ruleId, 'react/sort-comp', 'fails due to sort'); 74 | }); 75 | 76 | t.test('order: when random method after lifecycle methods', (t) => { 77 | t.plan(2); 78 | const result = lint(wrapComponent(` 79 | componentWillMount() {} 80 | componentDidMount() {} 81 | someMethod() {} 82 | setFoo() {} 83 | getFoo() {} 84 | setBar() {} 85 | renderDogs() {} 86 | render() { return
; } 87 | `)); 88 | 89 | t.ok(result.errorCount, 'fails'); 90 | t.equal(result.messages[0].ruleId, 'react/sort-comp', 'fails due to sort'); 91 | }); 92 | }); 93 | -------------------------------------------------------------------------------- /react/README.md: -------------------------------------------------------------------------------- 1 | # Airbnb React/JSX Style Guide 2 | 3 | *A mostly reasonable approach to React and JSX* 4 | 5 | ## Table of Contents 6 | 7 | 1. [Basic Rules](#basic-rules) 8 | 1. [Class vs `React.createClass` vs stateless](#class-vs-reactcreateclass-vs-stateless) 9 | 1. [Mixins](#mixins) 10 | 1. [Naming](#naming) 11 | 1. [Declaration](#declaration) 12 | 1. [Alignment](#alignment) 13 | 1. [Quotes](#quotes) 14 | 1. [Spacing](#spacing) 15 | 1. [Props](#props) 16 | 1. [Refs](#refs) 17 | 1. [Parentheses](#parentheses) 18 | 1. [Tags](#tags) 19 | 1. [Methods](#methods) 20 | 1. [Ordering](#ordering) 21 | 1. [`isMounted`](#ismounted) 22 | 23 | ## Basic Rules 24 | 25 | - Only include one React component per file. 26 | - 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). 27 | - Always use JSX syntax. 28 | - Do not use `React.createElement` unless you're initializing the app from a file that is not JSX. 29 | 30 | ## Class vs `React.createClass` vs stateless 31 | 32 | - If you have internal state and/or refs, prefer `class extends React.Component` over `React.createClass`. 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) 33 | 34 | ```jsx 35 | // bad 36 | const Listing = React.createClass({ 37 | // ... 38 | render() { 39 | return
{this.state.hello}
; 40 | } 41 | }); 42 | 43 | // good 44 | class Listing extends React.Component { 45 | // ... 46 | render() { 47 | return
{this.state.hello}
; 48 | } 49 | } 50 | ``` 51 | 52 | And if you don't have state or refs, prefer normal functions (not arrow functions) over classes: 53 | 54 | ```jsx 55 | // bad 56 | class Listing extends React.Component { 57 | render() { 58 | return
{this.props.hello}
; 59 | } 60 | } 61 | 62 | // bad (relying on function name inference is discouraged) 63 | const Listing = ({ hello }) => ( 64 |
{hello}
65 | ); 66 | 67 | // good 68 | function Listing({ hello }) { 69 | return
{hello}
; 70 | } 71 | ``` 72 | 73 | ## Mixins 74 | 75 | - [Do not use mixins](https://facebook.github.io/react/blog/2016/07/13/mixins-considered-harmful.html). 76 | 77 | > Why? Mixins introduce implicit dependencies, cause name clashes, and cause snowballing complexity. Most use cases for mixins can be accomplished in better ways via components, higher-order components, or utility modules. 78 | 79 | ## Naming 80 | 81 | - **Extensions**: Use `.jsx` extension for React components. 82 | - **Filename**: Use PascalCase for filenames. E.g., `ReservationCard.jsx`. 83 | - **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) 84 | 85 | ```jsx 86 | // bad 87 | import reservationCard from './ReservationCard'; 88 | 89 | // good 90 | import ReservationCard from './ReservationCard'; 91 | 92 | // bad 93 | const ReservationItem = ; 94 | 95 | // good 96 | const reservationItem = ; 97 | ``` 98 | 99 | - **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: 100 | 101 | ```jsx 102 | // bad 103 | import Footer from './Footer/Footer'; 104 | 105 | // bad 106 | import Footer from './Footer/index'; 107 | 108 | // good 109 | import Footer from './Footer'; 110 | ``` 111 | - **Higher-order Component Naming**: Use a composite of the higher-order component's name and the passed-in component's name as the `displayName` on the generated component. For example, the higher-order component `withFoo()`, when passed a component `Bar` should produce a component with a `displayName` of `withFoo(Bar)`. 112 | 113 | > Why? A component's `displayName` may be used by developer tools or in error messages, and having a value that clearly expresses this relationship helps people understand what is happening. 114 | 115 | ```jsx 116 | // bad 117 | export default function withFoo(WrappedComponent) { 118 | return function WithFoo(props) { 119 | return ; 120 | } 121 | } 122 | 123 | // good 124 | export default function withFoo(WrappedComponent) { 125 | function WithFoo(props) { 126 | return ; 127 | } 128 | 129 | const wrappedComponentName = WrappedComponent.displayName 130 | || WrappedComponent.name 131 | || 'Component'; 132 | 133 | WithFoo.displayName = `withFoo(${wrappedComponentName})`; 134 | return WithFoo; 135 | } 136 | ``` 137 | 138 | - **Props Naming**: Avoid using DOM component prop names for different purposes. 139 | 140 | > Why? People expect props like `style` and `className` to mean one specific thing. Varying this API for a subset of your app makes the code less readable and less maintainable, and may cause bugs. 141 | 142 | ```jsx 143 | // bad 144 | 145 | 146 | // good 147 | 148 | ``` 149 | 150 | ## Declaration 151 | 152 | - Do not use `displayName` for naming components. Instead, name the component by reference. 153 | 154 | ```jsx 155 | // bad 156 | export default React.createClass({ 157 | displayName: 'ReservationCard', 158 | // stuff goes here 159 | }); 160 | 161 | // good 162 | export default class ReservationCard extends React.Component { 163 | } 164 | ``` 165 | 166 | ## Alignment 167 | 168 | - 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) 169 | 170 | ```jsx 171 | // bad 172 | 174 | 175 | // good 176 | 180 | 181 | // if props fit in one line then keep it on the same line 182 | 183 | 184 | // children get indented normally 185 | 189 | 190 | 191 | ``` 192 | 193 | ## Quotes 194 | 195 | - Always use double quotes (`"`) for JSX attributes, but single quotes (`'`) for all other JS. eslint: [`jsx-quotes`](http://eslint.org/docs/rules/jsx-quotes) 196 | 197 | > Why? Regular HTML attributes also typically use double quotes instead of single, so JSX attributes mirror this convention. 198 | 199 | ```jsx 200 | // bad 201 | 202 | 203 | // good 204 | 205 | 206 | // bad 207 | 208 | 209 | // good 210 | 211 | ``` 212 | 213 | ## Spacing 214 | 215 | - Always include a single space in your self-closing tag. eslint: [`no-multi-spaces`](http://eslint.org/docs/rules/no-multi-spaces), [`react/jsx-tag-spacing`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-tag-spacing.md) 216 | 217 | ```jsx 218 | // bad 219 | 220 | 221 | // very bad 222 | 223 | 224 | // bad 225 | 227 | 228 | // good 229 | 230 | ``` 231 | 232 | - Do not pad JSX curly braces with spaces. eslint: [`react/jsx-curly-spacing`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-curly-spacing.md) 233 | 234 | ```jsx 235 | // bad 236 | 237 | 238 | // good 239 | 240 | ``` 241 | 242 | ## Props 243 | 244 | - Always use camelCase for prop names. 245 | 246 | ```jsx 247 | // bad 248 | 252 | 253 | // good 254 | 258 | ``` 259 | 260 | - Omit the value of the prop when it is explicitly `true`. eslint: [`react/jsx-boolean-value`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-boolean-value.md) 261 | 262 | ```jsx 263 | // bad 264 |
307 | 308 | // bad - abstract ARIA role 309 |
310 | 311 | // good 312 |
313 | ``` 314 | 315 | - Do not use `accessKey` on elements. eslint: [`jsx-a11y/no-access-key`](https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/no-access-key.md) 316 | 317 | > Why? Inconsistencies between keyboard shortcuts and keyboard commands used by people using screenreaders and keyboards complicate accessibility. 318 | 319 | ```jsx 320 | // bad 321 |
322 | 323 | // good 324 |
325 | ``` 326 | 327 | - Avoid using an array index as `key` prop, prefer a unique ID. ([why?](https://medium.com/@robinpokorny/index-as-a-key-is-an-anti-pattern-e0349aece318)) 328 | 329 | ```jsx 330 | // bad 331 | {todos.map((todo, index) => 332 | 336 | )} 337 | 338 | // good 339 | {todos.map(todo => ( 340 | 344 | ))} 345 | ``` 346 | 347 | - Always define explicit defaultProps for all non-required props. 348 | 349 | > Why? propTypes are a form of documentation, and providing defaultProps means the reader of your code doesn’t have to assume as much. In addition, it can mean that your code can omit certain type checks. 350 | 351 | ```jsx 352 | // bad 353 | function SFC({ foo, bar, children }) { 354 | return
{foo}{bar}{children}
; 355 | } 356 | SFC.propTypes = { 357 | foo: PropTypes.number.isRequired, 358 | bar: PropTypes.string, 359 | children: PropTypes.node, 360 | }; 361 | 362 | // good 363 | function SFC({ foo, bar, children }) { 364 | return
{foo}{bar}{children}
; 365 | } 366 | SFC.propTypes = { 367 | foo: PropTypes.number.isRequired, 368 | bar: PropTypes.string, 369 | children: PropTypes.node, 370 | }; 371 | SFC.defaultProps = { 372 | bar: '', 373 | children: null, 374 | }; 375 | ``` 376 | 377 | ## Refs 378 | 379 | - Always use ref callbacks. eslint: [`react/no-string-refs`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-string-refs.md) 380 | 381 | ```jsx 382 | // bad 383 | 386 | 387 | // good 388 | { this.myRef = ref; }} 390 | /> 391 | ``` 392 | 393 | ## Parentheses 394 | 395 | - Wrap JSX tags in parentheses when they span more than one line. eslint: [`react/jsx-wrap-multilines`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-wrap-multilines.md) 396 | 397 | ```jsx 398 | // bad 399 | render() { 400 | return 401 | 402 | ; 403 | } 404 | 405 | // good 406 | render() { 407 | return ( 408 | 409 | 410 | 411 | ); 412 | } 413 | 414 | // good, when single line 415 | render() { 416 | const body =
hello
; 417 | return {body}; 418 | } 419 | ``` 420 | 421 | ## Tags 422 | 423 | - 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) 424 | 425 | ```jsx 426 | // bad 427 | 428 | 429 | // good 430 | 431 | ``` 432 | 433 | - 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) 434 | 435 | ```jsx 436 | // bad 437 | 440 | 441 | // good 442 | 446 | ``` 447 | 448 | ## Methods 449 | 450 | - Use arrow functions to close over local variables. 451 | 452 | ```jsx 453 | function ItemList(props) { 454 | return ( 455 |
    456 | {props.items.map((item, index) => ( 457 | doSomethingWith(item.name, index)} 460 | /> 461 | ))} 462 |
463 | ); 464 | } 465 | ``` 466 | 467 | - 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) 468 | 469 | > Why? A bind call in the render path creates a brand new function on every single render. 470 | 471 | ```jsx 472 | // bad 473 | class extends React.Component { 474 | onClickDiv() { 475 | // do stuff 476 | } 477 | 478 | render() { 479 | return
; 480 | } 481 | } 482 | 483 | // good 484 | class extends React.Component { 485 | constructor(props) { 486 | super(props); 487 | 488 | this.onClickDiv = this.onClickDiv.bind(this); 489 | } 490 | 491 | onClickDiv() { 492 | // do stuff 493 | } 494 | 495 | render() { 496 | return
; 497 | } 498 | } 499 | ``` 500 | 501 | - Do not use underscore prefix for internal methods of a React component. 502 | > Why? Underscore prefixes are sometimes used as a convention in other languages to denote privacy. But, unlike those languages, there is no native support for privacy in JavaScript, everything is public. Regardless of your intentions, adding underscore prefixes to your properties does not actually make them private, and any property (underscore-prefixed or not) should be treated as being public. See issues [#1024](https://github.com/airbnb/javascript/issues/1024), and [#490](https://github.com/airbnb/javascript/issues/490) for a more in-depth discussion. 503 | 504 | ```jsx 505 | // bad 506 | React.createClass({ 507 | _onClickSubmit() { 508 | // do stuff 509 | }, 510 | 511 | // other stuff 512 | }); 513 | 514 | // good 515 | class extends React.Component { 516 | onClickSubmit() { 517 | // do stuff 518 | } 519 | 520 | // other stuff 521 | } 522 | ``` 523 | 524 | - Be sure to return a value in your `render` methods. eslint: [`react/require-render-return`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/require-render-return.md) 525 | 526 | ```jsx 527 | // bad 528 | render() { 529 | (
); 530 | } 531 | 532 | // good 533 | render() { 534 | return (
); 535 | } 536 | ``` 537 | 538 | ## Ordering 539 | 540 | - Ordering for `class extends React.Component`: 541 | 542 | 1. optional `static` methods 543 | 1. `constructor` 544 | 1. `getChildContext` 545 | 1. `componentWillMount` 546 | 1. `componentDidMount` 547 | 1. `componentWillReceiveProps` 548 | 1. `shouldComponentUpdate` 549 | 1. `componentWillUpdate` 550 | 1. `componentDidUpdate` 551 | 1. `componentWillUnmount` 552 | 1. *clickHandlers or eventHandlers* like `onClickSubmit()` or `onChangeDescription()` 553 | 1. *getter methods for `render`* like `getSelectReason()` or `getFooterContent()` 554 | 1. *optional render methods* like `renderNavigation()` or `renderProfilePicture()` 555 | 1. `render` 556 | 557 | - How to define `propTypes`, `defaultProps`, `contextTypes`, etc... 558 | 559 | ```jsx 560 | import React from 'react'; 561 | import PropTypes from 'prop-types'; 562 | 563 | const propTypes = { 564 | id: PropTypes.number.isRequired, 565 | url: PropTypes.string.isRequired, 566 | text: PropTypes.string, 567 | }; 568 | 569 | const defaultProps = { 570 | text: 'Hello World', 571 | }; 572 | 573 | class Link extends React.Component { 574 | static methodsAreOk() { 575 | return true; 576 | } 577 | 578 | render() { 579 | return {this.props.text}; 580 | } 581 | } 582 | 583 | Link.propTypes = propTypes; 584 | Link.defaultProps = defaultProps; 585 | 586 | export default Link; 587 | ``` 588 | 589 | - Ordering for `React.createClass`: eslint: [`react/sort-comp`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/sort-comp.md) 590 | 591 | 1. `displayName` 592 | 1. `propTypes` 593 | 1. `contextTypes` 594 | 1. `childContextTypes` 595 | 1. `mixins` 596 | 1. `statics` 597 | 1. `defaultProps` 598 | 1. `getDefaultProps` 599 | 1. `getInitialState` 600 | 1. `getChildContext` 601 | 1. `componentWillMount` 602 | 1. `componentDidMount` 603 | 1. `componentWillReceiveProps` 604 | 1. `shouldComponentUpdate` 605 | 1. `componentWillUpdate` 606 | 1. `componentDidUpdate` 607 | 1. `componentWillUnmount` 608 | 1. *clickHandlers or eventHandlers* like `onClickSubmit()` or `onChangeDescription()` 609 | 1. *getter methods for `render`* like `getSelectReason()` or `getFooterContent()` 610 | 1. *optional render methods* like `renderNavigation()` or `renderProfilePicture()` 611 | 1. `render` 612 | 613 | ## `isMounted` 614 | 615 | - Do not use `isMounted`. eslint: [`react/no-is-mounted`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-is-mounted.md) 616 | 617 | > Why? [`isMounted` is an anti-pattern][anti-pattern], is not available when using ES6 classes, and is on its way to being officially deprecated. 618 | 619 | [anti-pattern]: https://facebook.github.io/react/blog/2015/12/16/ismounted-antipattern.html 620 | 621 | ## Translation 622 | 623 | This JSX/React style guide is also available in other languages: 624 | 625 | - ![cn](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/China.png) **Chinese (Simplified)**: [JasonBoy/javascript](https://github.com/JasonBoy/javascript/tree/master/react) 626 | - ![tw](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Taiwan.png) **Chinese (Traditional)**: [jigsawye/javascript](https://github.com/jigsawye/javascript/tree/master/react) 627 | - ![es](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Spain.png) **Español**: [agrcrobles/javascript](https://github.com/agrcrobles/javascript/tree/master/react) 628 | - ![jp](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Japan.png) **Japanese**: [mitsuruog/javascript-style-guide](https://github.com/mitsuruog/javascript-style-guide/tree/master/react) 629 | - ![kr](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/South-Korea.png) **Korean**: [apple77y/javascript](https://github.com/apple77y/javascript/tree/master/react) 630 | - ![pl](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Poland.png) **Polish**: [pietraszekl/javascript](https://github.com/pietraszekl/javascript/tree/master/react) 631 | - ![Br](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Brazil.png) **Portuguese**: [ronal2do/javascript](https://github.com/ronal2do/airbnb-react-styleguide) 632 | - ![ru](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Russia.png) **Russian**: [leonidlebedev/javascript-airbnb](https://github.com/leonidlebedev/javascript-airbnb/tree/master/react) 633 | - ![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/tree/master/react) 634 | - ![ua](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Ukraine.png) **Ukrainian**: [ivanzusko/javascript](https://github.com/ivanzusko/javascript/tree/master/react) 635 | 636 | **[⬆ back to top](#table-of-contents)** 637 | --------------------------------------------------------------------------------