├── .gitignore ├── .travis.yml ├── README.md ├── es5 └── README.md ├── linters ├── .eslintrc ├── .jshintrc └── SublimeLinter │ └── SublimeLinter.sublime-settings ├── package.json ├── packages ├── eslint-config-airbnb-base │ ├── .eslintrc │ ├── 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 │ ├── .eslintrc │ ├── 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 /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "6" 4 | - "5" 5 | - "4" 6 | - "iojs" 7 | env: 8 | - 'TEST_DIR=packages/eslint-config-airbnb' 9 | - 'TEST_DIR=packages/eslint-config-airbnb-base' 10 | before_install: 11 | - 'cd $TEST_DIR' 12 | - 'if [ "${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' 13 | - 'if [ "${TRAVIS_NODE_VERSION}" != "0.6" ] && [ "${TRAVIS_NODE_VERSION}" != "0.9" ]; then npm install -g npm; fi' 14 | script: 15 | - 'npm run travis' 16 | sudo: false 17 | matrix: 18 | fast_finish: true 19 | allow_failures: 20 | - node_js: "iojs" 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Airbnb JavaScript Style Guide() { 2 | 3 | *A mostly reasonable approach to JavaScript* 4 | 5 | ## 此REPO只用于[React/JSX编码规范中文版](react/) 6 | -------------------------------------------------------------------------------- /es5/README.md: -------------------------------------------------------------------------------- 1 | [![Gitter](https://badges.gitter.im/Join Chat.svg)](https://gitter.im/airbnb/javascript?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) 2 | 3 | # Airbnb JavaScript Style Guide() { 4 | 5 | *A mostly reasonable approach to JavaScript* 6 | 7 | 8 | ## Table of Contents 9 | 10 | 1. [Types](#types) 11 | 1. [Objects](#objects) 12 | 1. [Arrays](#arrays) 13 | 1. [Strings](#strings) 14 | 1. [Functions](#functions) 15 | 1. [Properties](#properties) 16 | 1. [Variables](#variables) 17 | 1. [Hoisting](#hoisting) 18 | 1. [Comparison Operators & Equality](#comparison-operators--equality) 19 | 1. [Blocks](#blocks) 20 | 1. [Comments](#comments) 21 | 1. [Whitespace](#whitespace) 22 | 1. [Commas](#commas) 23 | 1. [Semicolons](#semicolons) 24 | 1. [Type Casting & Coercion](#type-casting--coercion) 25 | 1. [Naming Conventions](#naming-conventions) 26 | 1. [Accessors](#accessors) 27 | 1. [Constructors](#constructors) 28 | 1. [Events](#events) 29 | 1. [Modules](#modules) 30 | 1. [jQuery](#jquery) 31 | 1. [ECMAScript 5 Compatibility](#ecmascript-5-compatibility) 32 | 1. [Testing](#testing) 33 | 1. [Performance](#performance) 34 | 1. [Resources](#resources) 35 | 1. [In the Wild](#in-the-wild) 36 | 1. [Translation](#translation) 37 | 1. [The JavaScript Style Guide Guide](#the-javascript-style-guide-guide) 38 | 1. [Chat With Us About Javascript](#chat-with-us-about-javascript) 39 | 1. [Contributors](#contributors) 40 | 1. [License](#license) 41 | 42 | ## Types 43 | 44 | - **Primitives**: When you access a primitive type you work directly on its value. 45 | 46 | + `string` 47 | + `number` 48 | + `boolean` 49 | + `null` 50 | + `undefined` 51 | 52 | ```javascript 53 | var foo = 1; 54 | var bar = foo; 55 | 56 | bar = 9; 57 | 58 | console.log(foo, bar); // => 1, 9 59 | ``` 60 | - **Complex**: When you access a complex type you work on a reference to its value. 61 | 62 | + `object` 63 | + `array` 64 | + `function` 65 | 66 | ```javascript 67 | var foo = [1, 2]; 68 | var bar = foo; 69 | 70 | bar[0] = 9; 71 | 72 | console.log(foo[0], bar[0]); // => 9, 9 73 | ``` 74 | 75 | **[⬆ back to top](#table-of-contents)** 76 | 77 | ## Objects 78 | 79 | - Use the literal syntax for object creation. 80 | 81 | ```javascript 82 | // bad 83 | var item = new Object(); 84 | 85 | // good 86 | var item = {}; 87 | ``` 88 | 89 | - Don't use [reserved words](http://es5.github.io/#x7.6.1) as keys. It won't work in IE8. [More info](https://github.com/airbnb/javascript/issues/61). 90 | 91 | ```javascript 92 | // bad 93 | var superman = { 94 | default: { clark: 'kent' }, 95 | private: true 96 | }; 97 | 98 | // good 99 | var superman = { 100 | defaults: { clark: 'kent' }, 101 | hidden: true 102 | }; 103 | ``` 104 | 105 | - Use readable synonyms in place of reserved words. 106 | 107 | ```javascript 108 | // bad 109 | var superman = { 110 | class: 'alien' 111 | }; 112 | 113 | // bad 114 | var superman = { 115 | klass: 'alien' 116 | }; 117 | 118 | // good 119 | var superman = { 120 | type: 'alien' 121 | }; 122 | ``` 123 | 124 | **[⬆ back to top](#table-of-contents)** 125 | 126 | ## Arrays 127 | 128 | - Use the literal syntax for array creation. 129 | 130 | ```javascript 131 | // bad 132 | var items = new Array(); 133 | 134 | // good 135 | var items = []; 136 | ``` 137 | 138 | - Use Array#push instead of direct assignment to add items to an array. 139 | 140 | ```javascript 141 | var someStack = []; 142 | 143 | 144 | // bad 145 | someStack[someStack.length] = 'abracadabra'; 146 | 147 | // good 148 | someStack.push('abracadabra'); 149 | ``` 150 | 151 | - When you need to copy an array use Array#slice. [jsPerf](http://jsperf.com/converting-arguments-to-an-array/7) 152 | 153 | ```javascript 154 | var len = items.length; 155 | var itemsCopy = []; 156 | var i; 157 | 158 | // bad 159 | for (i = 0; i < len; i++) { 160 | itemsCopy[i] = items[i]; 161 | } 162 | 163 | // good 164 | itemsCopy = items.slice(); 165 | ``` 166 | 167 | - To convert an array-like object to an array, use Array#slice. 168 | 169 | ```javascript 170 | function trigger() { 171 | var args = Array.prototype.slice.call(arguments); 172 | ... 173 | } 174 | ``` 175 | 176 | **[⬆ back to top](#table-of-contents)** 177 | 178 | 179 | ## Strings 180 | 181 | - Use single quotes `''` for strings. 182 | 183 | ```javascript 184 | // bad 185 | var name = "Bob Parr"; 186 | 187 | // good 188 | var name = 'Bob Parr'; 189 | 190 | // bad 191 | var fullName = "Bob " + this.lastName; 192 | 193 | // good 194 | var fullName = 'Bob ' + this.lastName; 195 | ``` 196 | 197 | - Strings longer than 100 characters should be written across multiple lines using string concatenation. 198 | - Note: If overused, long strings with concatenation could impact performance. [jsPerf](http://jsperf.com/ya-string-concat) & [Discussion](https://github.com/airbnb/javascript/issues/40). 199 | 200 | ```javascript 201 | // bad 202 | var errorMessage = 'This is a super long error that was thrown because of Batman. When you stop to think about how Batman had anything to do with this, you would get nowhere fast.'; 203 | 204 | // bad 205 | var errorMessage = 'This is a super long error that was thrown because \ 206 | of Batman. When you stop to think about how Batman had anything to do \ 207 | with this, you would get nowhere \ 208 | fast.'; 209 | 210 | // good 211 | var errorMessage = 'This is a super long error that was thrown because ' + 212 | 'of Batman. When you stop to think about how Batman had anything to do ' + 213 | 'with this, you would get nowhere fast.'; 214 | ``` 215 | 216 | - When programmatically building up a string, use Array#join instead of string concatenation. Mostly for IE: [jsPerf](http://jsperf.com/string-vs-array-concat/2). 217 | 218 | ```javascript 219 | var items; 220 | var messages; 221 | var length; 222 | var i; 223 | 224 | messages = [{ 225 | state: 'success', 226 | message: 'This one worked.' 227 | }, { 228 | state: 'success', 229 | message: 'This one worked as well.' 230 | }, { 231 | state: 'error', 232 | message: 'This one did not work.' 233 | }]; 234 | 235 | length = messages.length; 236 | 237 | // bad 238 | function inbox(messages) { 239 | items = ''; 246 | } 247 | 248 | // good 249 | function inbox(messages) { 250 | items = []; 251 | 252 | for (i = 0; i < length; i++) { 253 | // use direct assignment in this case because we're micro-optimizing. 254 | items[i] = '
  • ' + messages[i].message + '
  • '; 255 | } 256 | 257 | return ''; 258 | } 259 | ``` 260 | 261 | **[⬆ back to top](#table-of-contents)** 262 | 263 | 264 | ## Functions 265 | 266 | - Function expressions: 267 | 268 | ```javascript 269 | // anonymous function expression 270 | var anonymous = function () { 271 | return true; 272 | }; 273 | 274 | // named function expression 275 | var named = function named() { 276 | return true; 277 | }; 278 | 279 | // immediately-invoked function expression (IIFE) 280 | (function () { 281 | console.log('Welcome to the Internet. Please follow me.'); 282 | }()); 283 | ``` 284 | 285 | - Never declare a function in a non-function block (if, while, etc). Assign the function to a variable instead. Browsers will allow you to do it, but they all interpret it differently, which is bad news bears. 286 | - **Note:** ECMA-262 defines a `block` as a list of statements. A function declaration is not a statement. [Read ECMA-262's note on this issue](http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf#page=97). 287 | 288 | ```javascript 289 | // bad 290 | if (currentUser) { 291 | function test() { 292 | console.log('Nope.'); 293 | } 294 | } 295 | 296 | // good 297 | var test; 298 | if (currentUser) { 299 | test = function test() { 300 | console.log('Yup.'); 301 | }; 302 | } 303 | ``` 304 | 305 | - Never name a parameter `arguments`. This will take precedence over the `arguments` object that is given to every function scope. 306 | 307 | ```javascript 308 | // bad 309 | function nope(name, options, arguments) { 310 | // ...stuff... 311 | } 312 | 313 | // good 314 | function yup(name, options, args) { 315 | // ...stuff... 316 | } 317 | ``` 318 | 319 | **[⬆ back to top](#table-of-contents)** 320 | 321 | 322 | 323 | ## Properties 324 | 325 | - Use dot notation when accessing properties. 326 | 327 | ```javascript 328 | var luke = { 329 | jedi: true, 330 | age: 28 331 | }; 332 | 333 | // bad 334 | var isJedi = luke['jedi']; 335 | 336 | // good 337 | var isJedi = luke.jedi; 338 | ``` 339 | 340 | - Use subscript notation `[]` when accessing properties with a variable. 341 | 342 | ```javascript 343 | var luke = { 344 | jedi: true, 345 | age: 28 346 | }; 347 | 348 | function getProp(prop) { 349 | return luke[prop]; 350 | } 351 | 352 | var isJedi = getProp('jedi'); 353 | ``` 354 | 355 | **[⬆ back to top](#table-of-contents)** 356 | 357 | 358 | ## Variables 359 | 360 | - Always use `var` to declare variables. Not doing so will result in global variables. We want to avoid polluting the global namespace. Captain Planet warned us of that. 361 | 362 | ```javascript 363 | // bad 364 | superPower = new SuperPower(); 365 | 366 | // good 367 | var superPower = new SuperPower(); 368 | ``` 369 | 370 | - Use one `var` declaration per variable. 371 | It's easier to add new variable declarations this way, and you never have 372 | to worry about swapping out a `;` for a `,` or introducing punctuation-only 373 | diffs. 374 | 375 | ```javascript 376 | // bad 377 | var items = getItems(), 378 | goSportsTeam = true, 379 | dragonball = 'z'; 380 | 381 | // bad 382 | // (compare to above, and try to spot the mistake) 383 | var items = getItems(), 384 | goSportsTeam = true; 385 | dragonball = 'z'; 386 | 387 | // good 388 | var items = getItems(); 389 | var goSportsTeam = true; 390 | var dragonball = 'z'; 391 | ``` 392 | 393 | - Declare unassigned variables last. This is helpful when later on you might need to assign a variable depending on one of the previous assigned variables. 394 | 395 | ```javascript 396 | // bad 397 | var i, len, dragonball, 398 | items = getItems(), 399 | goSportsTeam = true; 400 | 401 | // bad 402 | var i; 403 | var items = getItems(); 404 | var dragonball; 405 | var goSportsTeam = true; 406 | var len; 407 | 408 | // good 409 | var items = getItems(); 410 | var goSportsTeam = true; 411 | var dragonball; 412 | var length; 413 | var i; 414 | ``` 415 | 416 | - Assign variables at the top of their scope. This helps avoid issues with variable declaration and assignment hoisting related issues. 417 | 418 | ```javascript 419 | // bad 420 | function () { 421 | test(); 422 | console.log('doing stuff..'); 423 | 424 | //..other stuff.. 425 | 426 | var name = getName(); 427 | 428 | if (name === 'test') { 429 | return false; 430 | } 431 | 432 | return name; 433 | } 434 | 435 | // good 436 | function () { 437 | var name = getName(); 438 | 439 | test(); 440 | console.log('doing stuff..'); 441 | 442 | //..other stuff.. 443 | 444 | if (name === 'test') { 445 | return false; 446 | } 447 | 448 | return name; 449 | } 450 | 451 | // bad - unnecessary function call 452 | function () { 453 | var name = getName(); 454 | 455 | if (!arguments.length) { 456 | return false; 457 | } 458 | 459 | this.setFirstName(name); 460 | 461 | return true; 462 | } 463 | 464 | // good 465 | function () { 466 | var name; 467 | 468 | if (!arguments.length) { 469 | return false; 470 | } 471 | 472 | name = getName(); 473 | this.setFirstName(name); 474 | 475 | return true; 476 | } 477 | ``` 478 | 479 | **[⬆ back to top](#table-of-contents)** 480 | 481 | 482 | ## Hoisting 483 | 484 | - Variable declarations get hoisted to the top of their scope, but their assignment does not. 485 | 486 | ```javascript 487 | // we know this wouldn't work (assuming there 488 | // is no notDefined global variable) 489 | function example() { 490 | console.log(notDefined); // => throws a ReferenceError 491 | } 492 | 493 | // creating a variable declaration after you 494 | // reference the variable will work due to 495 | // variable hoisting. Note: the assignment 496 | // value of `true` is not hoisted. 497 | function example() { 498 | console.log(declaredButNotAssigned); // => undefined 499 | var declaredButNotAssigned = true; 500 | } 501 | 502 | // The interpreter is hoisting the variable 503 | // declaration to the top of the scope, 504 | // which means our example could be rewritten as: 505 | function example() { 506 | var declaredButNotAssigned; 507 | console.log(declaredButNotAssigned); // => undefined 508 | declaredButNotAssigned = true; 509 | } 510 | ``` 511 | 512 | - Anonymous function expressions hoist their variable name, but not the function assignment. 513 | 514 | ```javascript 515 | function example() { 516 | console.log(anonymous); // => undefined 517 | 518 | anonymous(); // => TypeError anonymous is not a function 519 | 520 | var anonymous = function () { 521 | console.log('anonymous function expression'); 522 | }; 523 | } 524 | ``` 525 | 526 | - Named function expressions hoist the variable name, not the function name or the function body. 527 | 528 | ```javascript 529 | function example() { 530 | console.log(named); // => undefined 531 | 532 | named(); // => TypeError named is not a function 533 | 534 | superPower(); // => ReferenceError superPower is not defined 535 | 536 | var named = function superPower() { 537 | console.log('Flying'); 538 | }; 539 | } 540 | 541 | // the same is true when the function name 542 | // is the same as the variable name. 543 | function example() { 544 | console.log(named); // => undefined 545 | 546 | named(); // => TypeError named is not a function 547 | 548 | var named = function named() { 549 | console.log('named'); 550 | } 551 | } 552 | ``` 553 | 554 | - Function declarations hoist their name and the function body. 555 | 556 | ```javascript 557 | function example() { 558 | superPower(); // => Flying 559 | 560 | function superPower() { 561 | console.log('Flying'); 562 | } 563 | } 564 | ``` 565 | 566 | - For more information refer to [JavaScript Scoping & Hoisting](http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting) by [Ben Cherry](http://www.adequatelygood.com/). 567 | 568 | **[⬆ back to top](#table-of-contents)** 569 | 570 | 571 | 572 | ## Comparison Operators & Equality 573 | 574 | - Use `===` and `!==` over `==` and `!=`. 575 | - Conditional statements such as the `if` statement evaluate their expression using coercion with the `ToBoolean` abstract method and always follow these simple rules: 576 | 577 | + **Objects** evaluate to **true** 578 | + **Undefined** evaluates to **false** 579 | + **Null** evaluates to **false** 580 | + **Booleans** evaluate to **the value of the boolean** 581 | + **Numbers** evaluate to **false** if **+0, -0, or NaN**, otherwise **true** 582 | + **Strings** evaluate to **false** if an empty string `''`, otherwise **true** 583 | 584 | ```javascript 585 | if ([0]) { 586 | // true 587 | // An array is an object, objects evaluate to true 588 | } 589 | ``` 590 | 591 | - Use shortcuts. 592 | 593 | ```javascript 594 | // bad 595 | if (name !== '') { 596 | // ...stuff... 597 | } 598 | 599 | // good 600 | if (name) { 601 | // ...stuff... 602 | } 603 | 604 | // bad 605 | if (collection.length > 0) { 606 | // ...stuff... 607 | } 608 | 609 | // good 610 | if (collection.length) { 611 | // ...stuff... 612 | } 613 | ``` 614 | 615 | - For more information see [Truth Equality and JavaScript](http://javascriptweblog.wordpress.com/2011/02/07/truth-equality-and-javascript/#more-2108) by Angus Croll. 616 | 617 | **[⬆ back to top](#table-of-contents)** 618 | 619 | 620 | ## Blocks 621 | 622 | - Use braces with all multi-line blocks. 623 | 624 | ```javascript 625 | // bad 626 | if (test) 627 | return false; 628 | 629 | // good 630 | if (test) return false; 631 | 632 | // good 633 | if (test) { 634 | return false; 635 | } 636 | 637 | // bad 638 | function () { return false; } 639 | 640 | // good 641 | function () { 642 | return false; 643 | } 644 | ``` 645 | 646 | - If you're using multi-line blocks with `if` and `else`, put `else` on the same line as your 647 | `if` block's closing brace. 648 | 649 | ```javascript 650 | // bad 651 | if (test) { 652 | thing1(); 653 | thing2(); 654 | } 655 | else { 656 | thing3(); 657 | } 658 | 659 | // good 660 | if (test) { 661 | thing1(); 662 | thing2(); 663 | } else { 664 | thing3(); 665 | } 666 | ``` 667 | 668 | 669 | **[⬆ back to top](#table-of-contents)** 670 | 671 | 672 | ## Comments 673 | 674 | - Use `/** ... */` for multi-line comments. Include a description, specify types and values for all parameters and return values. 675 | 676 | ```javascript 677 | // bad 678 | // make() returns a new element 679 | // based on the passed in tag name 680 | // 681 | // @param {String} tag 682 | // @return {Element} element 683 | function make(tag) { 684 | 685 | // ...stuff... 686 | 687 | return element; 688 | } 689 | 690 | // good 691 | /** 692 | * make() returns a new element 693 | * based on the passed in tag name 694 | * 695 | * @param {String} tag 696 | * @return {Element} element 697 | */ 698 | function make(tag) { 699 | 700 | // ...stuff... 701 | 702 | return element; 703 | } 704 | ``` 705 | 706 | - Use `//` for single line comments. Place single line comments on a newline above the subject of the comment. Put an empty line before the comment. 707 | 708 | ```javascript 709 | // bad 710 | var active = true; // is current tab 711 | 712 | // good 713 | // is current tab 714 | var active = true; 715 | 716 | // bad 717 | function getType() { 718 | console.log('fetching type...'); 719 | // set the default type to 'no type' 720 | var type = this._type || 'no type'; 721 | 722 | return type; 723 | } 724 | 725 | // good 726 | function getType() { 727 | console.log('fetching type...'); 728 | 729 | // set the default type to 'no type' 730 | var type = this._type || 'no type'; 731 | 732 | return type; 733 | } 734 | ``` 735 | 736 | - Prefixing your comments with `FIXME` or `TODO` helps other developers quickly understand if you're pointing out a problem that needs to be revisited, or if you're suggesting a solution to the problem that needs to be implemented. These are different than regular comments because they are actionable. The actions are `FIXME -- need to figure this out` or `TODO -- need to implement`. 737 | 738 | - Use `// FIXME:` to annotate problems. 739 | 740 | ```javascript 741 | function Calculator() { 742 | 743 | // FIXME: shouldn't use a global here 744 | total = 0; 745 | 746 | return this; 747 | } 748 | ``` 749 | 750 | - Use `// TODO:` to annotate solutions to problems. 751 | 752 | ```javascript 753 | function Calculator() { 754 | 755 | // TODO: total should be configurable by an options param 756 | this.total = 0; 757 | 758 | return this; 759 | } 760 | ``` 761 | 762 | **[⬆ back to top](#table-of-contents)** 763 | 764 | 765 | ## Whitespace 766 | 767 | - Use soft tabs set to 2 spaces. 768 | 769 | ```javascript 770 | // bad 771 | function () { 772 | ∙∙∙∙var name; 773 | } 774 | 775 | // bad 776 | function () { 777 | ∙var name; 778 | } 779 | 780 | // good 781 | function () { 782 | ∙∙var name; 783 | } 784 | ``` 785 | 786 | - Place 1 space before the leading brace. 787 | 788 | ```javascript 789 | // bad 790 | function test(){ 791 | console.log('test'); 792 | } 793 | 794 | // good 795 | function test() { 796 | console.log('test'); 797 | } 798 | 799 | // bad 800 | dog.set('attr',{ 801 | age: '1 year', 802 | breed: 'Bernese Mountain Dog' 803 | }); 804 | 805 | // good 806 | dog.set('attr', { 807 | age: '1 year', 808 | breed: 'Bernese Mountain Dog' 809 | }); 810 | ``` 811 | 812 | - Place 1 space before the opening parenthesis in control statements (`if`, `while` etc.). Place no space before the argument list in function calls and declarations. 813 | 814 | ```javascript 815 | // bad 816 | if(isJedi) { 817 | fight (); 818 | } 819 | 820 | // good 821 | if (isJedi) { 822 | fight(); 823 | } 824 | 825 | // bad 826 | function fight () { 827 | console.log ('Swooosh!'); 828 | } 829 | 830 | // good 831 | function fight() { 832 | console.log('Swooosh!'); 833 | } 834 | ``` 835 | 836 | - Set off operators with spaces. 837 | 838 | ```javascript 839 | // bad 840 | var x=y+5; 841 | 842 | // good 843 | var x = y + 5; 844 | ``` 845 | 846 | - End files with a single newline character. 847 | 848 | ```javascript 849 | // bad 850 | (function (global) { 851 | // ...stuff... 852 | })(this); 853 | ``` 854 | 855 | ```javascript 856 | // bad 857 | (function (global) { 858 | // ...stuff... 859 | })(this);↵ 860 | ↵ 861 | ``` 862 | 863 | ```javascript 864 | // good 865 | (function (global) { 866 | // ...stuff... 867 | })(this);↵ 868 | ``` 869 | 870 | - Use indentation when making long method chains. Use a leading dot, which 871 | emphasizes that the line is a method call, not a new statement. 872 | 873 | ```javascript 874 | // bad 875 | $('#items').find('.selected').highlight().end().find('.open').updateCount(); 876 | 877 | // bad 878 | $('#items'). 879 | find('.selected'). 880 | highlight(). 881 | end(). 882 | find('.open'). 883 | updateCount(); 884 | 885 | // good 886 | $('#items') 887 | .find('.selected') 888 | .highlight() 889 | .end() 890 | .find('.open') 891 | .updateCount(); 892 | 893 | // bad 894 | var leds = stage.selectAll('.led').data(data).enter().append('svg:svg').classed('led', true) 895 | .attr('width', (radius + margin) * 2).append('svg:g') 896 | .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')') 897 | .call(tron.led); 898 | 899 | // good 900 | var leds = stage.selectAll('.led') 901 | .data(data) 902 | .enter().append('svg:svg') 903 | .classed('led', true) 904 | .attr('width', (radius + margin) * 2) 905 | .append('svg:g') 906 | .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')') 907 | .call(tron.led); 908 | ``` 909 | 910 | - Leave a blank line after blocks and before the next statement 911 | 912 | ```javascript 913 | // bad 914 | if (foo) { 915 | return bar; 916 | } 917 | return baz; 918 | 919 | // good 920 | if (foo) { 921 | return bar; 922 | } 923 | 924 | return baz; 925 | 926 | // bad 927 | var obj = { 928 | foo: function () { 929 | }, 930 | bar: function () { 931 | } 932 | }; 933 | return obj; 934 | 935 | // good 936 | var obj = { 937 | foo: function () { 938 | }, 939 | 940 | bar: function () { 941 | } 942 | }; 943 | 944 | return obj; 945 | ``` 946 | 947 | 948 | **[⬆ back to top](#table-of-contents)** 949 | 950 | ## Commas 951 | 952 | - Leading commas: **Nope.** 953 | 954 | ```javascript 955 | // bad 956 | var story = [ 957 | once 958 | , upon 959 | , aTime 960 | ]; 961 | 962 | // good 963 | var story = [ 964 | once, 965 | upon, 966 | aTime 967 | ]; 968 | 969 | // bad 970 | var hero = { 971 | firstName: 'Bob' 972 | , lastName: 'Parr' 973 | , heroName: 'Mr. Incredible' 974 | , superPower: 'strength' 975 | }; 976 | 977 | // good 978 | var hero = { 979 | firstName: 'Bob', 980 | lastName: 'Parr', 981 | heroName: 'Mr. Incredible', 982 | superPower: 'strength' 983 | }; 984 | ``` 985 | 986 | - Additional trailing comma: **Nope.** This can cause problems with IE6/7 and IE9 if it's in quirksmode. Also, in some implementations of ES3 would add length to an array if it had an additional trailing comma. This was clarified in ES5 ([source](http://es5.github.io/#D)): 987 | 988 | > Edition 5 clarifies the fact that a trailing comma at the end of an ArrayInitialiser does not add to the length of the array. This is not a semantic change from Edition 3 but some implementations may have previously misinterpreted this. 989 | 990 | ```javascript 991 | // bad 992 | var hero = { 993 | firstName: 'Kevin', 994 | lastName: 'Flynn', 995 | }; 996 | 997 | var heroes = [ 998 | 'Batman', 999 | 'Superman', 1000 | ]; 1001 | 1002 | // good 1003 | var hero = { 1004 | firstName: 'Kevin', 1005 | lastName: 'Flynn' 1006 | }; 1007 | 1008 | var heroes = [ 1009 | 'Batman', 1010 | 'Superman' 1011 | ]; 1012 | ``` 1013 | 1014 | **[⬆ back to top](#table-of-contents)** 1015 | 1016 | 1017 | ## Semicolons 1018 | 1019 | - **Yup.** 1020 | 1021 | ```javascript 1022 | // bad 1023 | (function () { 1024 | var name = 'Skywalker' 1025 | return name 1026 | })() 1027 | 1028 | // good 1029 | (function () { 1030 | var name = 'Skywalker'; 1031 | return name; 1032 | })(); 1033 | 1034 | // good (guards against the function becoming an argument when two files with IIFEs are concatenated) 1035 | ;(function () { 1036 | var name = 'Skywalker'; 1037 | return name; 1038 | })(); 1039 | ``` 1040 | 1041 | [Read more](http://stackoverflow.com/a/7365214/1712802). 1042 | 1043 | **[⬆ back to top](#table-of-contents)** 1044 | 1045 | 1046 | ## Type Casting & Coercion 1047 | 1048 | - Perform type coercion at the beginning of the statement. 1049 | - Strings: 1050 | 1051 | ```javascript 1052 | // => this.reviewScore = 9; 1053 | 1054 | // bad 1055 | var totalScore = this.reviewScore + ''; 1056 | 1057 | // good 1058 | var totalScore = '' + this.reviewScore; 1059 | 1060 | // bad 1061 | var totalScore = '' + this.reviewScore + ' total score'; 1062 | 1063 | // good 1064 | var totalScore = this.reviewScore + ' total score'; 1065 | ``` 1066 | 1067 | - Use `parseInt` for Numbers and always with a radix for type casting. 1068 | 1069 | ```javascript 1070 | var inputValue = '4'; 1071 | 1072 | // bad 1073 | var val = new Number(inputValue); 1074 | 1075 | // bad 1076 | var val = +inputValue; 1077 | 1078 | // bad 1079 | var val = inputValue >> 0; 1080 | 1081 | // bad 1082 | var val = parseInt(inputValue); 1083 | 1084 | // good 1085 | var val = Number(inputValue); 1086 | 1087 | // good 1088 | var val = parseInt(inputValue, 10); 1089 | ``` 1090 | 1091 | - If for whatever reason you are doing something wild and `parseInt` is your bottleneck and need to use Bitshift for [performance reasons](http://jsperf.com/coercion-vs-casting/3), leave a comment explaining why and what you're doing. 1092 | 1093 | ```javascript 1094 | // good 1095 | /** 1096 | * parseInt was the reason my code was slow. 1097 | * Bitshifting the String to coerce it to a 1098 | * Number made it a lot faster. 1099 | */ 1100 | var val = inputValue >> 0; 1101 | ``` 1102 | 1103 | - **Note:** Be careful when using bitshift operations. Numbers are represented as [64-bit values](http://es5.github.io/#x4.3.19), but Bitshift operations always return a 32-bit integer ([source](http://es5.github.io/#x11.7)). Bitshift can lead to unexpected behavior for integer values larger than 32 bits. [Discussion](https://github.com/airbnb/javascript/issues/109). Largest signed 32-bit Int is 2,147,483,647: 1104 | 1105 | ```javascript 1106 | 2147483647 >> 0 //=> 2147483647 1107 | 2147483648 >> 0 //=> -2147483648 1108 | 2147483649 >> 0 //=> -2147483647 1109 | ``` 1110 | 1111 | - Booleans: 1112 | 1113 | ```javascript 1114 | var age = 0; 1115 | 1116 | // bad 1117 | var hasAge = new Boolean(age); 1118 | 1119 | // good 1120 | var hasAge = Boolean(age); 1121 | 1122 | // good 1123 | var hasAge = !!age; 1124 | ``` 1125 | 1126 | **[⬆ back to top](#table-of-contents)** 1127 | 1128 | 1129 | ## Naming Conventions 1130 | 1131 | - Avoid single letter names. Be descriptive with your naming. 1132 | 1133 | ```javascript 1134 | // bad 1135 | function q() { 1136 | // ...stuff... 1137 | } 1138 | 1139 | // good 1140 | function query() { 1141 | // ..stuff.. 1142 | } 1143 | ``` 1144 | 1145 | - Use camelCase when naming objects, functions, and instances. 1146 | 1147 | ```javascript 1148 | // bad 1149 | var OBJEcttsssss = {}; 1150 | var this_is_my_object = {}; 1151 | var o = {}; 1152 | function c() {} 1153 | 1154 | // good 1155 | var thisIsMyObject = {}; 1156 | function thisIsMyFunction() {} 1157 | ``` 1158 | 1159 | - Use PascalCase when naming constructors or classes. 1160 | 1161 | ```javascript 1162 | // bad 1163 | function user(options) { 1164 | this.name = options.name; 1165 | } 1166 | 1167 | var bad = new user({ 1168 | name: 'nope' 1169 | }); 1170 | 1171 | // good 1172 | function User(options) { 1173 | this.name = options.name; 1174 | } 1175 | 1176 | var good = new User({ 1177 | name: 'yup' 1178 | }); 1179 | ``` 1180 | 1181 | - Use a leading underscore `_` when naming private properties. 1182 | 1183 | ```javascript 1184 | // bad 1185 | this.__firstName__ = 'Panda'; 1186 | this.firstName_ = 'Panda'; 1187 | 1188 | // good 1189 | this._firstName = 'Panda'; 1190 | ``` 1191 | 1192 | - When saving a reference to `this` use `_this`. 1193 | 1194 | ```javascript 1195 | // bad 1196 | function () { 1197 | var self = this; 1198 | return function () { 1199 | console.log(self); 1200 | }; 1201 | } 1202 | 1203 | // bad 1204 | function () { 1205 | var that = this; 1206 | return function () { 1207 | console.log(that); 1208 | }; 1209 | } 1210 | 1211 | // good 1212 | function () { 1213 | var _this = this; 1214 | return function () { 1215 | console.log(_this); 1216 | }; 1217 | } 1218 | ``` 1219 | 1220 | - Name your functions. This is helpful for stack traces. 1221 | 1222 | ```javascript 1223 | // bad 1224 | var log = function (msg) { 1225 | console.log(msg); 1226 | }; 1227 | 1228 | // good 1229 | var log = function log(msg) { 1230 | console.log(msg); 1231 | }; 1232 | ``` 1233 | 1234 | - **Note:** IE8 and below exhibit some quirks with named function expressions. See [http://kangax.github.io/nfe/](http://kangax.github.io/nfe/) for more info. 1235 | 1236 | - If your file exports a single class, your filename should be exactly the name of the class. 1237 | ```javascript 1238 | // file contents 1239 | class CheckBox { 1240 | // ... 1241 | } 1242 | module.exports = CheckBox; 1243 | 1244 | // in some other file 1245 | // bad 1246 | var CheckBox = require('./checkBox'); 1247 | 1248 | // bad 1249 | var CheckBox = require('./check_box'); 1250 | 1251 | // good 1252 | var CheckBox = require('./CheckBox'); 1253 | ``` 1254 | 1255 | **[⬆ back to top](#table-of-contents)** 1256 | 1257 | 1258 | ## Accessors 1259 | 1260 | - Accessor functions for properties are not required. 1261 | - If you do make accessor functions use getVal() and setVal('hello'). 1262 | 1263 | ```javascript 1264 | // bad 1265 | dragon.age(); 1266 | 1267 | // good 1268 | dragon.getAge(); 1269 | 1270 | // bad 1271 | dragon.age(25); 1272 | 1273 | // good 1274 | dragon.setAge(25); 1275 | ``` 1276 | 1277 | - If the property is a boolean, use isVal() or hasVal(). 1278 | 1279 | ```javascript 1280 | // bad 1281 | if (!dragon.age()) { 1282 | return false; 1283 | } 1284 | 1285 | // good 1286 | if (!dragon.hasAge()) { 1287 | return false; 1288 | } 1289 | ``` 1290 | 1291 | - It's okay to create get() and set() functions, but be consistent. 1292 | 1293 | ```javascript 1294 | function Jedi(options) { 1295 | options || (options = {}); 1296 | var lightsaber = options.lightsaber || 'blue'; 1297 | this.set('lightsaber', lightsaber); 1298 | } 1299 | 1300 | Jedi.prototype.set = function set(key, val) { 1301 | this[key] = val; 1302 | }; 1303 | 1304 | Jedi.prototype.get = function get(key) { 1305 | return this[key]; 1306 | }; 1307 | ``` 1308 | 1309 | **[⬆ back to top](#table-of-contents)** 1310 | 1311 | 1312 | ## Constructors 1313 | 1314 | - Assign methods to the prototype object, instead of overwriting the prototype with a new object. Overwriting the prototype makes inheritance impossible: by resetting the prototype you'll overwrite the base! 1315 | 1316 | ```javascript 1317 | function Jedi() { 1318 | console.log('new jedi'); 1319 | } 1320 | 1321 | // bad 1322 | Jedi.prototype = { 1323 | fight: function fight() { 1324 | console.log('fighting'); 1325 | }, 1326 | 1327 | block: function block() { 1328 | console.log('blocking'); 1329 | } 1330 | }; 1331 | 1332 | // good 1333 | Jedi.prototype.fight = function fight() { 1334 | console.log('fighting'); 1335 | }; 1336 | 1337 | Jedi.prototype.block = function block() { 1338 | console.log('blocking'); 1339 | }; 1340 | ``` 1341 | 1342 | - Methods can return `this` to help with method chaining. 1343 | 1344 | ```javascript 1345 | // bad 1346 | Jedi.prototype.jump = function jump() { 1347 | this.jumping = true; 1348 | return true; 1349 | }; 1350 | 1351 | Jedi.prototype.setHeight = function setHeight(height) { 1352 | this.height = height; 1353 | }; 1354 | 1355 | var luke = new Jedi(); 1356 | luke.jump(); // => true 1357 | luke.setHeight(20); // => undefined 1358 | 1359 | // good 1360 | Jedi.prototype.jump = function jump() { 1361 | this.jumping = true; 1362 | return this; 1363 | }; 1364 | 1365 | Jedi.prototype.setHeight = function setHeight(height) { 1366 | this.height = height; 1367 | return this; 1368 | }; 1369 | 1370 | var luke = new Jedi(); 1371 | 1372 | luke.jump() 1373 | .setHeight(20); 1374 | ``` 1375 | 1376 | 1377 | - It's okay to write a custom toString() method, just make sure it works successfully and causes no side effects. 1378 | 1379 | ```javascript 1380 | function Jedi(options) { 1381 | options || (options = {}); 1382 | this.name = options.name || 'no name'; 1383 | } 1384 | 1385 | Jedi.prototype.getName = function getName() { 1386 | return this.name; 1387 | }; 1388 | 1389 | Jedi.prototype.toString = function toString() { 1390 | return 'Jedi - ' + this.getName(); 1391 | }; 1392 | ``` 1393 | 1394 | **[⬆ back to top](#table-of-contents)** 1395 | 1396 | 1397 | ## Events 1398 | 1399 | - When attaching data payloads to events (whether DOM events or something more proprietary like Backbone events), pass a hash instead of a raw value. This allows a subsequent contributor to add more data to the event payload without finding and updating every handler for the event. For example, instead of: 1400 | 1401 | ```js 1402 | // bad 1403 | $(this).trigger('listingUpdated', listing.id); 1404 | 1405 | ... 1406 | 1407 | $(this).on('listingUpdated', function (e, listingId) { 1408 | // do something with listingId 1409 | }); 1410 | ``` 1411 | 1412 | prefer: 1413 | 1414 | ```js 1415 | // good 1416 | $(this).trigger('listingUpdated', { listingId : listing.id }); 1417 | 1418 | ... 1419 | 1420 | $(this).on('listingUpdated', function (e, data) { 1421 | // do something with data.listingId 1422 | }); 1423 | ``` 1424 | 1425 | **[⬆ back to top](#table-of-contents)** 1426 | 1427 | 1428 | ## Modules 1429 | 1430 | - The module should start with a `!`. This ensures that if a malformed module forgets to include a final semicolon there aren't errors in production when the scripts get concatenated. [Explanation](https://github.com/airbnb/javascript/issues/44#issuecomment-13063933) 1431 | - The file should be named with camelCase, live in a folder with the same name, and match the name of the single export. 1432 | - Add a method called `noConflict()` that sets the exported module to the previous version and returns this one. 1433 | - Always declare `'use strict';` at the top of the module. 1434 | 1435 | ```javascript 1436 | // fancyInput/fancyInput.js 1437 | 1438 | !function (global) { 1439 | 'use strict'; 1440 | 1441 | var previousFancyInput = global.FancyInput; 1442 | 1443 | function FancyInput(options) { 1444 | this.options = options || {}; 1445 | } 1446 | 1447 | FancyInput.noConflict = function noConflict() { 1448 | global.FancyInput = previousFancyInput; 1449 | return FancyInput; 1450 | }; 1451 | 1452 | global.FancyInput = FancyInput; 1453 | }(this); 1454 | ``` 1455 | 1456 | **[⬆ back to top](#table-of-contents)** 1457 | 1458 | 1459 | ## jQuery 1460 | 1461 | - Prefix jQuery object variables with a `$`. 1462 | 1463 | ```javascript 1464 | // bad 1465 | var sidebar = $('.sidebar'); 1466 | 1467 | // good 1468 | var $sidebar = $('.sidebar'); 1469 | ``` 1470 | 1471 | - Cache jQuery lookups. 1472 | 1473 | ```javascript 1474 | // bad 1475 | function setSidebar() { 1476 | $('.sidebar').hide(); 1477 | 1478 | // ...stuff... 1479 | 1480 | $('.sidebar').css({ 1481 | 'background-color': 'pink' 1482 | }); 1483 | } 1484 | 1485 | // good 1486 | function setSidebar() { 1487 | var $sidebar = $('.sidebar'); 1488 | $sidebar.hide(); 1489 | 1490 | // ...stuff... 1491 | 1492 | $sidebar.css({ 1493 | 'background-color': 'pink' 1494 | }); 1495 | } 1496 | ``` 1497 | 1498 | - For DOM queries use Cascading `$('.sidebar ul')` or parent > child `$('.sidebar > ul')`. [jsPerf](http://jsperf.com/jquery-find-vs-context-sel/16) 1499 | - Use `find` with scoped jQuery object queries. 1500 | 1501 | ```javascript 1502 | // bad 1503 | $('ul', '.sidebar').hide(); 1504 | 1505 | // bad 1506 | $('.sidebar').find('ul').hide(); 1507 | 1508 | // good 1509 | $('.sidebar ul').hide(); 1510 | 1511 | // good 1512 | $('.sidebar > ul').hide(); 1513 | 1514 | // good 1515 | $sidebar.find('ul').hide(); 1516 | ``` 1517 | 1518 | **[⬆ back to top](#table-of-contents)** 1519 | 1520 | 1521 | ## ECMAScript 5 Compatibility 1522 | 1523 | - Refer to [Kangax](https://twitter.com/kangax/)'s ES5 [compatibility table](http://kangax.github.com/es5-compat-table/). 1524 | 1525 | **[⬆ back to top](#table-of-contents)** 1526 | 1527 | 1528 | ## Testing 1529 | 1530 | - **Yup.** 1531 | 1532 | ```javascript 1533 | function () { 1534 | return true; 1535 | } 1536 | ``` 1537 | 1538 | **[⬆ back to top](#table-of-contents)** 1539 | 1540 | 1541 | ## Performance 1542 | 1543 | - [On Layout & Web Performance](http://kellegous.com/j/2013/01/26/layout-performance/) 1544 | - [String vs Array Concat](http://jsperf.com/string-vs-array-concat/2) 1545 | - [Try/Catch Cost In a Loop](http://jsperf.com/try-catch-in-loop-cost) 1546 | - [Bang Function](http://jsperf.com/bang-function) 1547 | - [jQuery Find vs Context, Selector](http://jsperf.com/jquery-find-vs-context-sel/13) 1548 | - [innerHTML vs textContent for script text](http://jsperf.com/innerhtml-vs-textcontent-for-script-text) 1549 | - [Long String Concatenation](http://jsperf.com/ya-string-concat) 1550 | - Loading... 1551 | 1552 | **[⬆ back to top](#table-of-contents)** 1553 | 1554 | 1555 | ## Resources 1556 | 1557 | 1558 | **Read This** 1559 | 1560 | - [Annotated ECMAScript 5.1](http://es5.github.com/) 1561 | 1562 | **Tools** 1563 | 1564 | - Code Style Linters 1565 | + [JSHint](http://www.jshint.com/) - [Airbnb Style .jshintrc](https://github.com/airbnb/javascript/blob/master/linters/.jshintrc) 1566 | + [JSCS](https://github.com/jscs-dev/node-jscs) - [Airbnb Style Preset](https://github.com/jscs-dev/node-jscs/blob/master/presets/airbnb.json) 1567 | 1568 | **Other Style Guides** 1569 | 1570 | - [Google JavaScript Style Guide](http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml) 1571 | - [jQuery Core Style Guidelines](http://docs.jquery.com/JQuery_Core_Style_Guidelines) 1572 | - [Principles of Writing Consistent, Idiomatic JavaScript](https://github.com/rwldrn/idiomatic.js/) 1573 | - [JavaScript Standard Style](https://github.com/feross/standard) 1574 | 1575 | **Other Styles** 1576 | 1577 | - [Naming this in nested functions](https://gist.github.com/4135065) - Christian Johansen 1578 | - [Conditional Callbacks](https://github.com/airbnb/javascript/issues/52) - Ross Allen 1579 | - [Popular JavaScript Coding Conventions on Github](http://sideeffect.kr/popularconvention/#javascript) - JeongHoon Byun 1580 | - [Multiple var statements in JavaScript, not superfluous](http://benalman.com/news/2012/05/multiple-var-statements-javascript/) - Ben Alman 1581 | 1582 | **Further Reading** 1583 | 1584 | - [Understanding JavaScript Closures](http://javascriptweblog.wordpress.com/2010/10/25/understanding-javascript-closures/) - Angus Croll 1585 | - [Basic JavaScript for the impatient programmer](http://www.2ality.com/2013/06/basic-javascript.html) - Dr. Axel Rauschmayer 1586 | - [You Might Not Need jQuery](http://youmightnotneedjquery.com/) - Zack Bloom & Adam Schwartz 1587 | - [ES6 Features](https://github.com/lukehoban/es6features) - Luke Hoban 1588 | - [Frontend Guidelines](https://github.com/bendc/frontend-guidelines) - Benjamin De Cock 1589 | 1590 | **Books** 1591 | 1592 | - [JavaScript: The Good Parts](http://www.amazon.com/JavaScript-Good-Parts-Douglas-Crockford/dp/0596517742) - Douglas Crockford 1593 | - [JavaScript Patterns](http://www.amazon.com/JavaScript-Patterns-Stoyan-Stefanov/dp/0596806752) - Stoyan Stefanov 1594 | - [Pro JavaScript Design Patterns](http://www.amazon.com/JavaScript-Design-Patterns-Recipes-Problem-Solution/dp/159059908X) - Ross Harmes and Dustin Diaz 1595 | - [High Performance Web Sites: Essential Knowledge for Front-End Engineers](http://www.amazon.com/High-Performance-Web-Sites-Essential/dp/0596529309) - Steve Souders 1596 | - [Maintainable JavaScript](http://www.amazon.com/Maintainable-JavaScript-Nicholas-C-Zakas/dp/1449327680) - Nicholas C. Zakas 1597 | - [JavaScript Web Applications](http://www.amazon.com/JavaScript-Web-Applications-Alex-MacCaw/dp/144930351X) - Alex MacCaw 1598 | - [Pro JavaScript Techniques](http://www.amazon.com/Pro-JavaScript-Techniques-John-Resig/dp/1590597273) - John Resig 1599 | - [Smashing Node.js: JavaScript Everywhere](http://www.amazon.com/Smashing-Node-js-JavaScript-Everywhere-Magazine/dp/1119962595) - Guillermo Rauch 1600 | - [Secrets of the JavaScript Ninja](http://www.amazon.com/Secrets-JavaScript-Ninja-John-Resig/dp/193398869X) - John Resig and Bear Bibeault 1601 | - [Human JavaScript](http://humanjavascript.com/) - Henrik Joreteg 1602 | - [Superhero.js](http://superherojs.com/) - Kim Joar Bekkelund, Mads Mobæk, & Olav Bjorkoy 1603 | - [JSBooks](http://jsbooks.revolunet.com/) - Julien Bouquillon 1604 | - [Third Party JavaScript](http://manning.com/vinegar/) - Ben Vinegar and Anton Kovalyov 1605 | - [Effective JavaScript: 68 Specific Ways to Harness the Power of JavaScript](http://amzn.com/0321812182) - David Herman 1606 | - [Eloquent JavaScript](http://eloquentjavascript.net) - Marijn Haverbeke 1607 | - [You Don't Know JS](https://github.com/getify/You-Dont-Know-JS) - Kyle Simpson 1608 | 1609 | **Blogs** 1610 | 1611 | - [DailyJS](http://dailyjs.com/) 1612 | - [JavaScript Weekly](http://javascriptweekly.com/) 1613 | - [JavaScript, JavaScript...](http://javascriptweblog.wordpress.com/) 1614 | - [Bocoup Weblog](http://weblog.bocoup.com/) 1615 | - [Adequately Good](http://www.adequatelygood.com/) 1616 | - [NCZOnline](http://www.nczonline.net/) 1617 | - [Perfection Kills](http://perfectionkills.com/) 1618 | - [Ben Alman](http://benalman.com/) 1619 | - [Dmitry Baranovskiy](http://dmitry.baranovskiy.com/) 1620 | - [Dustin Diaz](http://dustindiaz.com/) 1621 | - [nettuts](http://net.tutsplus.com/?s=javascript) 1622 | 1623 | **Podcasts** 1624 | 1625 | - [JavaScript Jabber](http://devchat.tv/js-jabber/) 1626 | 1627 | 1628 | **[⬆ back to top](#table-of-contents)** 1629 | 1630 | ## In the Wild 1631 | 1632 | This is a list of organizations that are using this style guide. Send us a pull request or open an issue and we'll add you to the list. 1633 | 1634 | - **Aan Zee**: [AanZee/javascript](https://github.com/AanZee/javascript) 1635 | - **Adult Swim**: [adult-swim/javascript](https://github.com/adult-swim/javascript) 1636 | - **Airbnb**: [airbnb/javascript](https://github.com/airbnb/javascript) 1637 | - **Apartmint**: [apartmint/javascript](https://github.com/apartmint/javascript) 1638 | - **Avalara**: [avalara/javascript](https://github.com/avalara/javascript) 1639 | - **Billabong**: [billabong/javascript](https://github.com/billabong/javascript) 1640 | - **Compass Learning**: [compasslearning/javascript-style-guide](https://github.com/compasslearning/javascript-style-guide) 1641 | - **DailyMotion**: [dailymotion/javascript](https://github.com/dailymotion/javascript) 1642 | - **Digitpaint** [digitpaint/javascript](https://github.com/digitpaint/javascript) 1643 | - **Evernote**: [evernote/javascript-style-guide](https://github.com/evernote/javascript-style-guide) 1644 | - **ExactTarget**: [ExactTarget/javascript](https://github.com/ExactTarget/javascript) 1645 | - **Flexberry**: [Flexberry/javascript-style-guide](https://github.com/Flexberry/javascript-style-guide) 1646 | - **Gawker Media**: [gawkermedia/javascript](https://github.com/gawkermedia/javascript) 1647 | - **General Electric**: [GeneralElectric/javascript](https://github.com/GeneralElectric/javascript) 1648 | - **GoodData**: [gooddata/gdc-js-style](https://github.com/gooddata/gdc-js-style) 1649 | - **Grooveshark**: [grooveshark/javascript](https://github.com/grooveshark/javascript) 1650 | - **How About We**: [howaboutwe/javascript](https://github.com/howaboutwe/javascript) 1651 | - **InfoJobs**: [InfoJobs/JavaScript-Style-Guide](https://github.com/InfoJobs/JavaScript-Style-Guide) 1652 | - **Intent Media**: [intentmedia/javascript](https://github.com/intentmedia/javascript) 1653 | - **Jam3**: [Jam3/Javascript-Code-Conventions](https://github.com/Jam3/Javascript-Code-Conventions) 1654 | - **JSSolutions**: [JSSolutions/javascript](https://github.com/JSSolutions/javascript) 1655 | - **Kinetica Solutions**: [kinetica/javascript](https://github.com/kinetica/javascript) 1656 | - **Mighty Spring**: [mightyspring/javascript](https://github.com/mightyspring/javascript) 1657 | - **MinnPost**: [MinnPost/javascript](https://github.com/MinnPost/javascript) 1658 | - **ModCloth**: [modcloth/javascript](https://github.com/modcloth/javascript) 1659 | - **Money Advice Service**: [moneyadviceservice/javascript](https://github.com/moneyadviceservice/javascript) 1660 | - **Muber**: [muber/javascript](https://github.com/muber/javascript) 1661 | - **National Geographic**: [natgeo/javascript](https://github.com/natgeo/javascript) 1662 | - **National Park Service**: [nationalparkservice/javascript](https://github.com/nationalparkservice/javascript) 1663 | - **Nimbl3**: [nimbl3/javascript](https://github.com/nimbl3/javascript) 1664 | - **Nordic Venture Family**: [CodeDistillery/javascript](https://github.com/CodeDistillery/javascript) 1665 | - **Orion Health**: [orionhealth/javascript](https://github.com/orionhealth/javascript) 1666 | - **Peerby**: [Peerby/javascript](https://github.com/Peerby/javascript) 1667 | - **Razorfish**: [razorfish/javascript-style-guide](https://github.com/razorfish/javascript-style-guide) 1668 | - **reddit**: [reddit/styleguide/javascript](https://github.com/reddit/styleguide/tree/master/javascript) 1669 | - **REI**: [reidev/js-style-guide](https://github.com/reidev/js-style-guide) 1670 | - **Ripple**: [ripple/javascript-style-guide](https://github.com/ripple/javascript-style-guide) 1671 | - **SeekingAlpha**: [seekingalpha/javascript-style-guide](https://github.com/seekingalpha/javascript-style-guide) 1672 | - **Shutterfly**: [shutterfly/javascript](https://github.com/shutterfly/javascript) 1673 | - **StudentSphere**: [studentsphere/javascript](https://github.com/studentsphere/javascript) 1674 | - **Super**: [SuperJobs/javascript](https://github.com/SuperJobs/javascript) 1675 | - **SysGarage**: [sysgarage/javascript-style-guide](https://github.com/sysgarage/javascript-style-guide) 1676 | - **Target**: [target/javascript](https://github.com/target/javascript) 1677 | - **TheLadders**: [TheLadders/javascript](https://github.com/TheLadders/javascript) 1678 | - **T4R Technology**: [T4R-Technology/javascript](https://github.com/T4R-Technology/javascript) 1679 | - **VoxFeed**: [VoxFeed/javascript-style-guide](https://github.com/VoxFeed/javascript-style-guide) 1680 | - **Weggo**: [Weggo/javascript](https://github.com/Weggo/javascript) 1681 | - **Zillow**: [zillow/javascript](https://github.com/zillow/javascript) 1682 | - **ZocDoc**: [ZocDoc/javascript](https://github.com/ZocDoc/javascript) 1683 | 1684 | ## Translation 1685 | 1686 | This style guide is also available in other languages: 1687 | 1688 | - ![br](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Brazil.png) **Brazilian Portuguese**: [armoucar/javascript-style-guide](https://github.com/armoucar/javascript-style-guide) 1689 | - ![bg](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Bulgaria.png) **Bulgarian**: [borislavvv/javascript](https://github.com/borislavvv/javascript) 1690 | - ![ca](https://raw.githubusercontent.com/fpmweb/javascript-style-guide/master/img/catala.png) **Catalan**: [fpmweb/javascript-style-guide](https://github.com/fpmweb/javascript-style-guide) 1691 | - ![tw](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Taiwan.png) **Chinese(Traditional)**: [jigsawye/javascript](https://github.com/jigsawye/javascript) 1692 | - ![cn](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/China.png) **Chinese(Simplified)**: [sivan/javascript-style-guide](https://github.com/sivan/javascript-style-guide) 1693 | - ![fr](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/France.png) **French**: [nmussy/javascript-style-guide](https://github.com/nmussy/javascript-style-guide) 1694 | - ![de](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Germany.png) **German**: [timofurrer/javascript-style-guide](https://github.com/timofurrer/javascript-style-guide) 1695 | - ![it](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Italy.png) **Italian**: [sinkswim/javascript-style-guide](https://github.com/sinkswim/javascript-style-guide) 1696 | - ![jp](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Japan.png) **Japanese**: [mitsuruog/javacript-style-guide](https://github.com/mitsuruog/javacript-style-guide) 1697 | - ![kr](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/South-Korea.png) **Korean**: [tipjs/javascript-style-guide](https://github.com/tipjs/javascript-style-guide) 1698 | - ![pl](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Poland.png) **Polish**: [mjurczyk/javascript](https://github.com/mjurczyk/javascript) 1699 | - ![ru](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Russia.png) **Russian**: [uprock/javascript](https://github.com/uprock/javascript) 1700 | - ![es](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Spain.png) **Spanish**: [paolocarrasco/javascript-style-guide](https://github.com/paolocarrasco/javascript-style-guide) 1701 | - ![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) 1702 | 1703 | ## The JavaScript Style Guide Guide 1704 | 1705 | - [Reference](https://github.com/airbnb/javascript/wiki/The-JavaScript-Style-Guide-Guide) 1706 | 1707 | ## Chat With Us About JavaScript 1708 | 1709 | - Find us on [gitter](https://gitter.im/airbnb/javascript). 1710 | 1711 | ## Contributors 1712 | 1713 | - [View Contributors](https://github.com/airbnb/javascript/graphs/contributors) 1714 | 1715 | 1716 | ## License 1717 | 1718 | (The MIT License) 1719 | 1720 | Copyright (c) 2014 Airbnb 1721 | 1722 | Permission is hereby granted, free of charge, to any person obtaining 1723 | a copy of this software and associated documentation files (the 1724 | 'Software'), to deal in the Software without restriction, including 1725 | without limitation the rights to use, copy, modify, merge, publish, 1726 | distribute, sublicense, and/or sell copies of the Software, and to 1727 | permit persons to whom the Software is furnished to do so, subject to 1728 | the following conditions: 1729 | 1730 | The above copyright notice and this permission notice shall be 1731 | included in all copies or substantial portions of the Software. 1732 | 1733 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 1734 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 1735 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 1736 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 1737 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 1738 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 1739 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 1740 | 1741 | **[⬆ back to top](#table-of-contents)** 1742 | 1743 | # }; 1744 | -------------------------------------------------------------------------------- /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/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 | "test": "npm run --silent test:config && npm run --silent test:config:base", 10 | "test:config": "cd packages/eslint-config-airbnb; npm test", 11 | "test:config:base": "cd packages/eslint-config-airbnb-base; npm test", 12 | "travis": "npm run --silent travis:config && npm run --silent travis:config:base", 13 | "travis:config": "cd packages/eslint-config-airbnb; npm run travis", 14 | "travis:config:base": "cd packages/eslint-config-airbnb-base; npm run travis" 15 | }, 16 | "repository": { 17 | "type": "git", 18 | "url": "https://github.com/airbnb/javascript.git" 19 | }, 20 | "keywords": [ 21 | "style guide", 22 | "lint", 23 | "airbnb", 24 | "es6", 25 | "es2015", 26 | "react", 27 | "jsx" 28 | ], 29 | "author": "Harrison Shoff (https://twitter.com/hshoff)", 30 | "license": "MIT", 31 | "bugs": { 32 | "url": "https://github.com/airbnb/javascript/issues" 33 | }, 34 | "homepage": "https://github.com/airbnb/javascript" 35 | } 36 | -------------------------------------------------------------------------------- /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/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 3.0.1 / 2016-05-08 2 | ================== 3 | - [patch] re-disable `no-extra-parens` (#869, #867) 4 | 5 | 3.0.0 / 2016-05-07 6 | ================== 7 | - [breaking] enable `import/no-mutable-exports` 8 | - [breaking] enable `no-class-assign` rule, to pair with `no-func-assign` 9 | - [breaking] widen `no-extra-parens` to include everything, except `nestedBinaryExpressions` 10 | - [breaking] Re-enabling `newline-per-chained-call` (#748) 11 | - [minor] enable `import/no-amd` 12 | - [patch] enable `import/no-duplicates` 13 | - [deps] update `eslint`, `eslint-plugin-import`, `eslint-find-rules` 14 | 15 | 2.0.0 / 2016-04-29 16 | ================== 17 | - [breaking] enable `no-unsafe-finally` rule 18 | - [semver-minor] enable `no-useless-computed-key` rule 19 | - [deps] update `eslint`, `eslint-plugin-import` 20 | 21 | 1.0.4 / 2016-04-26 22 | ================== 23 | - [deps] update `eslint-find-rules`, `eslint-plugin-import` 24 | 25 | 1.0.3 / 2016-04-21 26 | ================== 27 | - [patch: loosen rules] Allow empty class/object methods 28 | 29 | 1.0.2 / 2016-04-20 30 | ================== 31 | - [patch: loosen rules] Allow `break` (#840) 32 | 33 | 1.0.1 / 2016-04-19 34 | ================== 35 | - [patch: loosen rules] Allow `== null` (#542) 36 | 37 | 1.0.0 / 2016-04-19 38 | ================== 39 | - Initial commmit; moved content over from `eslint-config-airbnb` package. 40 | -------------------------------------------------------------------------------- /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 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 | 1. `npm install --save-dev eslint-config-airbnb-base eslint-plugin-import eslint` 16 | 2. add `"extends": "airbnb-base"` to your .eslintrc 17 | 18 | ### eslint-config-airbnb-base/legacy 19 | 20 | Lints ES5 and below. Requires `eslint` and `eslint-plugin-import`. 21 | 22 | 1. `npm install --save-dev eslint-config-airbnb-base eslint-plugin-import eslint` 23 | 2. add `"extends": "airbnb-base/legacy"` to your .eslintrc 24 | 25 | 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. 26 | 27 | ## Improving this config 28 | 29 | 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? 30 | 31 | You can run tests with `npm test`. 32 | 33 | You can make sure this module lints with itself using `npm run lint`. 34 | -------------------------------------------------------------------------------- /packages/eslint-config-airbnb-base/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: [ 3 | './legacy', 4 | './rules/es6', 5 | './rules/imports', 6 | ].map(require.resolve), 7 | parserOptions: { 8 | ecmaVersion: 7, 9 | sourceType: 'module', 10 | }, 11 | rules: { 12 | strict: 2, 13 | } 14 | }; 15 | -------------------------------------------------------------------------------- /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 | ecmaFeatures: {}, 17 | globals: {}, 18 | rules: {} 19 | }; 20 | -------------------------------------------------------------------------------- /packages/eslint-config-airbnb-base/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "eslint-config-airbnb-base", 3 | "version": "3.0.1", 4 | "description": "Airbnb's base JS ESLint config, following our styleguide", 5 | "main": "index.js", 6 | "scripts": { 7 | "lint": "eslint .", 8 | "tests-only": "babel-tape-runner ./test/test-*.js", 9 | "pretest": "eslint-find-rules --unused", 10 | "test": "npm run --silent lint && npm run --silent tests-only", 11 | "travis": "npm run --silent test" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "https://github.com/airbnb/javascript" 16 | }, 17 | "keywords": [ 18 | "eslint", 19 | "eslintconfig", 20 | "config", 21 | "airbnb", 22 | "javascript", 23 | "styleguide" 24 | ], 25 | "author": "Jake Teton-Landis (https://twitter.com/@jitl)", 26 | "contributors": [ 27 | { 28 | "name": "Jake Teton-Landis", 29 | "url": "https://twitter.com/jitl" 30 | }, 31 | { 32 | "name": "Jordan Harband", 33 | "email": "ljharb@gmail.com", 34 | "url": "http://ljharb.codes" 35 | }, 36 | { 37 | "name": "Harrison Shoff", 38 | "url": "https://twitter.com/hshoff" 39 | } 40 | ], 41 | "license": "MIT", 42 | "bugs": { 43 | "url": "https://github.com/airbnb/javascript/issues" 44 | }, 45 | "homepage": "https://github.com/airbnb/javascript", 46 | "devDependencies": { 47 | "babel-tape-runner": "^1.3.1", 48 | "eslint": "^2.10.1", 49 | "eslint-find-rules": "^1.9.2", 50 | "eslint-plugin-import": "^1.8.0", 51 | "tape": "^4.5.1" 52 | }, 53 | "peerDependencies": { 54 | "eslint": "^2.10.1", 55 | "eslint-plugin-import": "^1.8.0" 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /packages/eslint-config-airbnb-base/rules/best-practices.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | rules: { 3 | // enforces getter/setter pairs in objects 4 | 'accessor-pairs': 0, 5 | 6 | // enforces return statements in callbacks of array's methods 7 | // http://eslint.org/docs/rules/array-callback-return 8 | 'array-callback-return': 2, 9 | 10 | // treat var statements as if they were block scoped 11 | 'block-scoped-var': 2, 12 | 13 | // specify the maximum cyclomatic complexity allowed in a program 14 | complexity: [0, 11], 15 | 16 | // require return statements to either always or never specify values 17 | 'consistent-return': 2, 18 | 19 | // specify curly brace conventions for all control statements 20 | curly: [2, 'multi-line'], 21 | 22 | // require default case in switch statements 23 | 'default-case': [2, { commentPattern: '^no default$' }], 24 | 25 | // encourages use of dot notation whenever possible 26 | 'dot-notation': [2, { allowKeywords: true }], 27 | 28 | // enforces consistent newlines before or after dots 29 | 'dot-location': 0, 30 | 31 | // require the use of === and !== 32 | // http://eslint.org/docs/rules/eqeqeq 33 | eqeqeq: [2, 'allow-null'], 34 | 35 | // make sure for-in loops have an if statement 36 | 'guard-for-in': 2, 37 | 38 | // disallow the use of alert, confirm, and prompt 39 | 'no-alert': 1, 40 | 41 | // disallow use of arguments.caller or arguments.callee 42 | 'no-caller': 2, 43 | 44 | // disallow lexical declarations in case/default clauses 45 | // http://eslint.org/docs/rules/no-case-declarations.html 46 | 'no-case-declarations': 2, 47 | 48 | // disallow division operators explicitly at beginning of regular expression 49 | 'no-div-regex': 0, 50 | 51 | // disallow else after a return in an if 52 | 'no-else-return': 2, 53 | 54 | // disallow empty functions, except for standalone funcs/arrows 55 | // http://eslint.org/docs/rules/no-empty-function 56 | 'no-empty-function': [2, { 57 | allow: [ 58 | 'arrowFunctions', 59 | 'functions', 60 | 'methods', 61 | ] 62 | }], 63 | 64 | // disallow empty destructuring patterns 65 | // http://eslint.org/docs/rules/no-empty-pattern 66 | 'no-empty-pattern': 2, 67 | 68 | // disallow comparisons to null without a type-checking operator 69 | 'no-eq-null': 0, 70 | 71 | // disallow use of eval() 72 | 'no-eval': 2, 73 | 74 | // disallow adding to native types 75 | 'no-extend-native': 2, 76 | 77 | // disallow unnecessary function binding 78 | 'no-extra-bind': 2, 79 | 80 | // disallow Unnecessary Labels 81 | // http://eslint.org/docs/rules/no-extra-label 82 | 'no-extra-label': 2, 83 | 84 | // disallow fallthrough of case statements 85 | 'no-fallthrough': 2, 86 | 87 | // disallow the use of leading or trailing decimal points in numeric literals 88 | 'no-floating-decimal': 2, 89 | 90 | // disallow the type conversions with shorter notations 91 | 'no-implicit-coercion': 0, 92 | 93 | // disallow var and named functions in global scope 94 | // http://eslint.org/docs/rules/no-implicit-globals 95 | 'no-implicit-globals': 0, 96 | 97 | // disallow use of eval()-like methods 98 | 'no-implied-eval': 2, 99 | 100 | // disallow this keywords outside of classes or class-like objects 101 | 'no-invalid-this': 0, 102 | 103 | // disallow usage of __iterator__ property 104 | 'no-iterator': 2, 105 | 106 | // disallow use of labels for anything other then loops and switches 107 | 'no-labels': [2, { allowLoop: false, allowSwitch: false }], 108 | 109 | // disallow unnecessary nested blocks 110 | 'no-lone-blocks': 2, 111 | 112 | // disallow creation of functions within loops 113 | 'no-loop-func': 2, 114 | 115 | // disallow magic numbers 116 | // http://eslint.org/docs/rules/no-magic-numbers 117 | 'no-magic-numbers': [0, { 118 | ignore: [], 119 | ignoreArrayIndexes: true, 120 | enforceConst: true, 121 | detectObjects: false, 122 | }], 123 | 124 | // disallow use of multiple spaces 125 | 'no-multi-spaces': 2, 126 | 127 | // disallow use of multiline strings 128 | 'no-multi-str': 2, 129 | 130 | // disallow reassignments of native objects 131 | 'no-native-reassign': 2, 132 | 133 | // disallow use of new operator when not part of the assignment or comparison 134 | 'no-new': 2, 135 | 136 | // disallow use of new operator for Function object 137 | 'no-new-func': 2, 138 | 139 | // disallows creating new instances of String, Number, and Boolean 140 | 'no-new-wrappers': 2, 141 | 142 | // disallow use of (old style) octal literals 143 | 'no-octal': 2, 144 | 145 | // disallow use of octal escape sequences in string literals, such as 146 | // var foo = 'Copyright \251'; 147 | 'no-octal-escape': 2, 148 | 149 | // disallow reassignment of function parameters 150 | // disallow parameter object manipulation 151 | // rule: http://eslint.org/docs/rules/no-param-reassign.html 152 | 'no-param-reassign': [2, { props: true }], 153 | 154 | // disallow usage of __proto__ property 155 | 'no-proto': 2, 156 | 157 | // disallow declaring the same variable more then once 158 | 'no-redeclare': 2, 159 | 160 | // disallow use of assignment in return statement 161 | 'no-return-assign': 2, 162 | 163 | // disallow use of `javascript:` urls. 164 | 'no-script-url': 2, 165 | 166 | // disallow self assignment 167 | // http://eslint.org/docs/rules/no-self-assign 168 | 'no-self-assign': 2, 169 | 170 | // disallow comparisons where both sides are exactly the same 171 | 'no-self-compare': 2, 172 | 173 | // disallow use of comma operator 174 | 'no-sequences': 2, 175 | 176 | // restrict what can be thrown as an exception 177 | 'no-throw-literal': 2, 178 | 179 | // disallow unmodified conditions of loops 180 | // http://eslint.org/docs/rules/no-unmodified-loop-condition 181 | 'no-unmodified-loop-condition': 0, 182 | 183 | // disallow usage of expressions in statement position 184 | 'no-unused-expressions': 2, 185 | 186 | // disallow unused labels 187 | // http://eslint.org/docs/rules/no-unused-labels 188 | 'no-unused-labels': 2, 189 | 190 | // disallow unnecessary .call() and .apply() 191 | 'no-useless-call': 0, 192 | 193 | // disallow useless string concatenation 194 | // http://eslint.org/docs/rules/no-useless-concat 195 | 'no-useless-concat': 2, 196 | 197 | // disallow unnecessary string escaping 198 | // http://eslint.org/docs/rules/no-useless-escape 199 | 'no-useless-escape': 2, 200 | 201 | // disallow use of void operator 202 | 'no-void': 0, 203 | 204 | // disallow usage of configurable warning terms in comments: e.g. todo 205 | 'no-warning-comments': [0, { terms: ['todo', 'fixme', 'xxx'], location: 'start' }], 206 | 207 | // disallow use of the with statement 208 | 'no-with': 2, 209 | 210 | // require use of the second argument for parseInt() 211 | radix: 2, 212 | 213 | // requires to declare all vars on top of their containing scope 214 | 'vars-on-top': 2, 215 | 216 | // require immediate function invocation to be wrapped in parentheses 217 | // http://eslint.org/docs/rules/wrap-iife.html 218 | 'wrap-iife': [2, 'outside'], 219 | 220 | // require or disallow Yoda conditions 221 | yoda: 2 222 | } 223 | }; 224 | -------------------------------------------------------------------------------- /packages/eslint-config-airbnb-base/rules/errors.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | rules: { 3 | // require trailing commas in multiline object literals 4 | 'comma-dangle': [2, 'always-multiline'], 5 | 6 | // disallow assignment in conditional expressions 7 | 'no-cond-assign': [2, 'always'], 8 | 9 | // disallow use of console 10 | 'no-console': 1, 11 | 12 | // disallow use of constant expressions in conditions 13 | 'no-constant-condition': 1, 14 | 15 | // disallow control characters in regular expressions 16 | 'no-control-regex': 2, 17 | 18 | // disallow use of debugger 19 | 'no-debugger': 2, 20 | 21 | // disallow duplicate arguments in functions 22 | 'no-dupe-args': 2, 23 | 24 | // disallow duplicate keys when creating object literals 25 | 'no-dupe-keys': 2, 26 | 27 | // disallow a duplicate case label. 28 | 'no-duplicate-case': 2, 29 | 30 | // disallow empty statements 31 | 'no-empty': 2, 32 | 33 | // disallow the use of empty character classes in regular expressions 34 | 'no-empty-character-class': 2, 35 | 36 | // disallow assigning to the exception in a catch block 37 | 'no-ex-assign': 2, 38 | 39 | // disallow double-negation boolean casts in a boolean context 40 | 'no-extra-boolean-cast': 0, 41 | 42 | // disallow unnecessary parentheses 43 | // http://eslint.org/docs/rules/no-extra-parens 44 | 'no-extra-parens': [0, 'all', { 45 | conditionalAssign: true, 46 | nestedBinaryExpressions: false, 47 | returnAssign: false, 48 | }], 49 | 50 | // disallow unnecessary semicolons 51 | 'no-extra-semi': 2, 52 | 53 | // disallow overwriting functions written as function declarations 54 | 'no-func-assign': 2, 55 | 56 | // disallow function or variable declarations in nested blocks 57 | 'no-inner-declarations': 2, 58 | 59 | // disallow invalid regular expression strings in the RegExp constructor 60 | 'no-invalid-regexp': 2, 61 | 62 | // disallow irregular whitespace outside of strings and comments 63 | 'no-irregular-whitespace': 2, 64 | 65 | // disallow negation of the left operand of an in expression 66 | 'no-negated-in-lhs': 2, 67 | 68 | // disallow the use of object properties of the global object (Math and JSON) as functions 69 | 'no-obj-calls': 2, 70 | 71 | // disallow multiple spaces in a regular expression literal 72 | 'no-regex-spaces': 2, 73 | 74 | // disallow sparse arrays 75 | 'no-sparse-arrays': 2, 76 | 77 | // Avoid code that looks like two expressions but is actually one 78 | 'no-unexpected-multiline': 0, 79 | 80 | // disallow unreachable statements after a return, throw, continue, or break statement 81 | 'no-unreachable': 2, 82 | 83 | // disallow return/throw/break/continue inside finally blocks 84 | // http://eslint.org/docs/rules/no-unsafe-finally 85 | 'no-unsafe-finally': 2, 86 | 87 | // disallow comparisons with the value NaN 88 | 'use-isnan': 2, 89 | 90 | // ensure JSDoc comments are valid 91 | // http://eslint.org/docs/rules/valid-jsdoc 92 | 'valid-jsdoc': 0, 93 | 94 | // ensure that the results of typeof are compared against a valid string 95 | 'valid-typeof': 2 96 | } 97 | }; 98 | -------------------------------------------------------------------------------- /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 | 'arrow-body-style': [2, 'as-needed'], 18 | 19 | // require parens in arrow function arguments 20 | 'arrow-parens': 0, 21 | 22 | // require space before/after arrow function's arrow 23 | // http://eslint.org/docs/rules/arrow-spacing 24 | 'arrow-spacing': [2, { before: true, after: true }], 25 | 26 | // verify super() callings in constructors 27 | 'constructor-super': 0, 28 | 29 | // enforce the spacing around the * in generator functions 30 | // http://eslint.org/docs/rules/generator-star-spacing 31 | 'generator-star-spacing': [2, { before: false, after: true }], 32 | 33 | // disallow modifying variables of class declarations 34 | // http://eslint.org/docs/rules/no-class-assign 35 | 'no-class-assign': 2, 36 | 37 | // disallow arrow functions where they could be confused with comparisons 38 | // http://eslint.org/docs/rules/no-confusing-arrow 39 | 'no-confusing-arrow': [2, { 40 | allowParens: true, 41 | }], 42 | 43 | // disallow modifying variables that are declared using const 44 | 'no-const-assign': 2, 45 | 46 | // disallow duplicate class members 47 | // http://eslint.org/docs/rules/no-dupe-class-members 48 | 'no-dupe-class-members': 2, 49 | 50 | // disallow importing from the same path more than once 51 | // http://eslint.org/docs/rules/no-duplicate-imports 52 | 'no-duplicate-imports': 2, 53 | 54 | // disallow symbol constructor 55 | // http://eslint.org/docs/rules/no-new-symbol 56 | 'no-new-symbol': 2, 57 | 58 | // disallow specific imports 59 | // http://eslint.org/docs/rules/no-restricted-imports 60 | 'no-restricted-imports': 0, 61 | 62 | // disallow to use this/super before super() calling in constructors. 63 | 'no-this-before-super': 0, 64 | 65 | // disallow useless computed property keys 66 | // http://eslint.org/docs/rules/no-useless-computed-key 67 | 'no-useless-computed-key': 2, 68 | 69 | // disallow unnecessary constructor 70 | // http://eslint.org/docs/rules/no-useless-constructor 71 | 'no-useless-constructor': 2, 72 | 73 | // require let or const instead of var 74 | 'no-var': 2, 75 | 76 | // require method and property shorthand syntax for object literals 77 | // http://eslint.org/docs/rules/object-shorthand 78 | 'object-shorthand': [2, 'always', { 79 | ignoreConstructors: false, 80 | avoidQuotes: true, 81 | }], 82 | 83 | // suggest using arrow functions as callbacks 84 | 'prefer-arrow-callback': [2, { 85 | allowNamedFunctions: false, 86 | allowUnboundThis: true, 87 | }], 88 | 89 | // suggest using of const declaration for variables that are never modified after declared 90 | 'prefer-const': [2, { 91 | destructuring: 'any', 92 | ignoreReadBeforeAssign: true, 93 | }], 94 | 95 | // suggest using Reflect methods where applicable 96 | 'prefer-reflect': 0, 97 | 98 | // use rest parameters instead of arguments 99 | // http://eslint.org/docs/rules/prefer-rest-params 100 | 'prefer-rest-params': 2, 101 | 102 | // suggest using the spread operator instead of .apply() 103 | 'prefer-spread': 0, 104 | 105 | // suggest using template literals instead of string concatenation 106 | // http://eslint.org/docs/rules/prefer-template 107 | 'prefer-template': 2, 108 | 109 | // disallow generator functions that do not have yield 110 | 'require-yield': 0, 111 | 112 | // import sorting 113 | // http://eslint.org/docs/rules/sort-imports 114 | 'sort-imports': 0, 115 | 116 | // enforce usage of spacing in template strings 117 | // http://eslint.org/docs/rules/template-curly-spacing 118 | 'template-curly-spacing': 2, 119 | 120 | // enforce spacing around the * in yield* expressions 121 | // http://eslint.org/docs/rules/yield-star-spacing 122 | 'yield-star-spacing': [2, 'after'] 123 | } 124 | }; 125 | -------------------------------------------------------------------------------- /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 | }, 20 | 21 | rules: { 22 | // Static analysis: 23 | 24 | // ensure imports point to files/modules that can be resolved 25 | // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-unresolved.md 26 | 'import/no-unresolved': [2, { commonjs: true }], 27 | 28 | // ensure named imports coupled with named exports 29 | // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/named.md#when-not-to-use-it 30 | 'import/named': 0, 31 | 32 | // ensure default import coupled with default export 33 | // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/default.md#when-not-to-use-it 34 | 'import/default': 0, 35 | 36 | // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/namespace.md 37 | 'import/namespace': 0, 38 | 39 | // Helpful warnings: 40 | 41 | // disallow invalid exports, e.g. multiple defaults 42 | // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/export.md 43 | 'import/export': 2, 44 | 45 | // do not allow a default import name to match a named export 46 | // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-named-as-default.md 47 | // TODO: enable 48 | 'import/no-named-as-default': 0, 49 | 50 | // warn on accessing default export property names that are also named exports 51 | // TODO: enable? 52 | // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-named-as-default-member.md 53 | 'import/no-named-as-default-member': 0, 54 | 55 | // disallow use of jsdoc-marked-deprecated imports 56 | // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-deprecated.md 57 | 'import/no-deprecated': 0, 58 | 59 | // Forbid the use of extraneous packages 60 | // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-extraneous-dependencies.md 61 | // TODO: enable 62 | 'import/no-extraneous-dependencies': [0, { 63 | devDependencies: false, 64 | optionalDependencies: false, 65 | }], 66 | 67 | // Forbid mutable exports 68 | // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-mutable-exports.md 69 | 'import/no-mutable-exports': 2, 70 | 71 | // Module systems: 72 | 73 | // disallow require() 74 | // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-commonjs.md 75 | 'import/no-commonjs': 0, 76 | 77 | // disallow AMD require/define 78 | // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-amd.md 79 | 'import/no-amd': 2, 80 | 81 | // No Node.js builtin modules 82 | // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-nodejs-modules.md 83 | 'import/no-nodejs-modules': 0, 84 | 85 | // Style guide: 86 | 87 | // disallow non-import statements appearing before import statements 88 | // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/imports-first.md 89 | 'import/imports-first': [2, 'absolute-first'], 90 | 91 | // disallow duplicate imports 92 | // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-duplicates.md 93 | 'import/no-duplicates': 2, 94 | 95 | // disallow namespace imports 96 | // TODO: enable? 97 | // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-namespace.md 98 | 'import/no-namespace': 0, 99 | 100 | // Ensure consistent use of file extension within the import path 101 | // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/extensions.md 102 | // TODO: enable 103 | 'import/extensions': [0, 'never'], 104 | 105 | // Enforce a convention in module import order 106 | // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/order.md 107 | // TODO: enable? 108 | 'import/order': [0, { 109 | groups: ['builtin', 'external', 'internal', 'parent', 'sibling', 'index'], 110 | 'newlines-between': 'never', 111 | }], 112 | 113 | // Require a newline after the last import/require in a group 114 | // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/newline-after-import.md 115 | // TODO: enable 116 | 'import/newline-after-import': 0, 117 | 118 | // Require modules with a single export to use a default export 119 | // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/prefer-default-export.md 120 | // TODO: enable 121 | 'import/prefer-default-export': 0 122 | } 123 | }; 124 | -------------------------------------------------------------------------------- /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': 0, 9 | 10 | // require all requires be top-level 11 | // http://eslint.org/docs/rules/global-require 12 | 'global-require': 2, 13 | 14 | // enforces error handling in callbacks (node environment) 15 | 'handle-callback-err': 0, 16 | 17 | // disallow mixing regular variable and require declarations 18 | 'no-mixed-requires': [0, false], 19 | 20 | // disallow use of new operator with the require function 21 | 'no-new-require': 0, 22 | 23 | // disallow string concatenation with __dirname and __filename 24 | 'no-path-concat': 0, 25 | 26 | // disallow use of process.env 27 | 'no-process-env': 0, 28 | 29 | // disallow process.exit() 30 | 'no-process-exit': 0, 31 | 32 | // restrict usage of specified node modules 33 | 'no-restricted-modules': 0, 34 | 35 | // disallow use of synchronous methods (off by default) 36 | 'no-sync': 0 37 | } 38 | }; 39 | -------------------------------------------------------------------------------- /packages/eslint-config-airbnb-base/rules/strict.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | rules: { 3 | // babel inserts `'use strict';` for us 4 | strict: [2, 'never'] 5 | } 6 | }; 7 | -------------------------------------------------------------------------------- /packages/eslint-config-airbnb-base/rules/style.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | rules: { 3 | // enforce spacing inside array brackets 4 | 'array-bracket-spacing': [2, 'never'], 5 | 6 | // enforce spacing inside single-line blocks 7 | // http://eslint.org/docs/rules/block-spacing 8 | 'block-spacing': [2, 'always'], 9 | 10 | // enforce one true brace style 11 | 'brace-style': [2, '1tbs', { allowSingleLine: true }], 12 | 13 | // require camel case names 14 | camelcase: [2, { properties: 'never' }], 15 | 16 | // enforce spacing before and after comma 17 | 'comma-spacing': [2, { before: false, after: true }], 18 | 19 | // enforce one true comma style 20 | 'comma-style': [2, 'last'], 21 | 22 | // disallow padding inside computed properties 23 | 'computed-property-spacing': [2, 'never'], 24 | 25 | // enforces consistent naming when capturing the current execution context 26 | 'consistent-this': 0, 27 | 28 | // enforce newline at the end of file, with no multiple empty lines 29 | 'eol-last': 2, 30 | 31 | // require function expressions to have a name 32 | 'func-names': 1, 33 | 34 | // enforces use of function declarations or expressions 35 | 'func-style': 0, 36 | 37 | // Blacklist certain identifiers to prevent them being used 38 | // http://eslint.org/docs/rules/id-blacklist 39 | 'id-blacklist': 0, 40 | 41 | // this option enforces minimum and maximum identifier lengths 42 | // (variable names, property names etc.) 43 | 'id-length': 0, 44 | 45 | // require identifiers to match the provided regular expression 46 | 'id-match': 0, 47 | 48 | // this option sets a specific tab width for your code 49 | // http://eslint.org/docs/rules/indent 50 | indent: [2, 2, { SwitchCase: 1, VariableDeclarator: 1 }], 51 | 52 | // specify whether double or single quotes should be used in JSX attributes 53 | // http://eslint.org/docs/rules/jsx-quotes 54 | 'jsx-quotes': 0, 55 | 56 | // enforces spacing between keys and values in object literal properties 57 | 'key-spacing': [2, { beforeColon: false, afterColon: true }], 58 | 59 | // require a space before & after certain keywords 60 | 'keyword-spacing': [2, { 61 | before: true, 62 | after: true, 63 | overrides: { 64 | return: { after: true }, 65 | throw: { after: true }, 66 | case: { after: true } 67 | } 68 | }], 69 | 70 | // disallow mixed 'LF' and 'CRLF' as linebreaks 71 | 'linebreak-style': 0, 72 | 73 | // enforces empty lines around comments 74 | 'lines-around-comment': 0, 75 | 76 | // specify the maximum depth that blocks can be nested 77 | 'max-depth': [0, 4], 78 | 79 | // specify the maximum length of a line in your program 80 | // http://eslint.org/docs/rules/max-len 81 | 'max-len': [2, 100, 2, { 82 | ignoreUrls: true, 83 | ignoreComments: false 84 | }], 85 | 86 | // specify the maximum depth callbacks can be nested 87 | 'max-nested-callbacks': 0, 88 | 89 | // limits the number of parameters that can be used in the function declaration. 90 | 'max-params': [0, 3], 91 | 92 | // specify the maximum number of statement allowed in a function 93 | 'max-statements': [0, 10], 94 | 95 | // restrict the number of statements per line 96 | // http://eslint.org/docs/rules/max-statements-per-line 97 | 'max-statements-per-line': [0, { max: 1 }], 98 | 99 | // require a capital letter for constructors 100 | 'new-cap': [2, { newIsCap: true }], 101 | 102 | // disallow the omission of parentheses when invoking a constructor with no arguments 103 | 'new-parens': 0, 104 | 105 | // allow/disallow an empty newline after var statement 106 | 'newline-after-var': 0, 107 | 108 | // http://eslint.org/docs/rules/newline-before-return 109 | 'newline-before-return': 0, 110 | 111 | // enforces new line after each method call in the chain to make it 112 | // more readable and easy to maintain 113 | // http://eslint.org/docs/rules/newline-per-chained-call 114 | 'newline-per-chained-call': [2, { ignoreChainWithDepth: 3 }], 115 | 116 | // disallow use of the Array constructor 117 | 'no-array-constructor': 2, 118 | 119 | // disallow use of bitwise operators 120 | 'no-bitwise': 0, 121 | 122 | // disallow use of the continue statement 123 | 'no-continue': 0, 124 | 125 | // disallow comments inline after code 126 | 'no-inline-comments': 0, 127 | 128 | // disallow if as the only statement in an else block 129 | 'no-lonely-if': 0, 130 | 131 | // disallow mixed spaces and tabs for indentation 132 | 'no-mixed-spaces-and-tabs': 2, 133 | 134 | // disallow multiple empty lines and only one newline at the end 135 | 'no-multiple-empty-lines': [2, { max: 2, maxEOF: 1 }], 136 | 137 | // disallow negated conditions 138 | // http://eslint.org/docs/rules/no-negated-condition 139 | 'no-negated-condition': 0, 140 | 141 | // disallow nested ternary expressions 142 | 'no-nested-ternary': 2, 143 | 144 | // disallow use of the Object constructor 145 | 'no-new-object': 2, 146 | 147 | // disallow use of unary operators, ++ and -- 148 | 'no-plusplus': 0, 149 | 150 | // disallow certain syntax forms 151 | // http://eslint.org/docs/rules/no-restricted-syntax 152 | 'no-restricted-syntax': [ 153 | 2, 154 | 'DebuggerStatement', 155 | 'ForInStatement', 156 | 'LabeledStatement', 157 | 'WithStatement', 158 | ], 159 | 160 | // disallow space between function identifier and application 161 | 'no-spaced-func': 2, 162 | 163 | // disallow the use of ternary operators 164 | 'no-ternary': 0, 165 | 166 | // disallow trailing whitespace at the end of lines 167 | 'no-trailing-spaces': 2, 168 | 169 | // disallow dangling underscores in identifiers 170 | 'no-underscore-dangle': [2, { allowAfterThis: false }], 171 | 172 | // disallow the use of Boolean literals in conditional expressions 173 | // also, prefer `a || b` over `a ? a : b` 174 | // http://eslint.org/docs/rules/no-unneeded-ternary 175 | 'no-unneeded-ternary': [2, { defaultAssignment: false }], 176 | 177 | // disallow whitespace before properties 178 | // http://eslint.org/docs/rules/no-whitespace-before-property 179 | 'no-whitespace-before-property': 2, 180 | 181 | // require padding inside curly braces 182 | 'object-curly-spacing': [2, 'always'], 183 | 184 | // enforce "same line" or "multiple line" on object properties. 185 | // http://eslint.org/docs/rules/object-property-newline 186 | // TODO: enable when https://github.com/eslint/eslint/issues/5667#issuecomment-219334864 is resolved 187 | 'object-property-newline': [0, { 188 | allowMultiplePropertiesPerLine: true, 189 | }], 190 | 191 | // allow just one var statement per function 192 | 'one-var': [2, 'never'], 193 | 194 | // require a newline around variable declaration 195 | // http://eslint.org/docs/rules/one-var-declaration-per-line 196 | 'one-var-declaration-per-line': [2, 'always'], 197 | 198 | // require assignment operator shorthand where possible or prohibit it entirely 199 | 'operator-assignment': 0, 200 | 201 | // enforce operators to be placed before or after line breaks 202 | 'operator-linebreak': 0, 203 | 204 | // enforce padding within blocks 205 | 'padded-blocks': [2, 'never'], 206 | 207 | // require quotes around object literal property names 208 | // http://eslint.org/docs/rules/quote-props.html 209 | 'quote-props': [2, 'as-needed', { keywords: false, unnecessary: true, numbers: false }], 210 | 211 | // specify whether double or single quotes should be used 212 | quotes: [2, 'single', { avoidEscape: true }], 213 | 214 | // do not require jsdoc 215 | // http://eslint.org/docs/rules/require-jsdoc 216 | 'require-jsdoc': 0, 217 | 218 | // require or disallow use of semicolons instead of ASI 219 | semi: [2, 'always'], 220 | 221 | // enforce spacing before and after semicolons 222 | 'semi-spacing': [2, { before: false, after: true }], 223 | 224 | // sort variables within the same declaration block 225 | 'sort-vars': 0, 226 | 227 | // require or disallow space before blocks 228 | 'space-before-blocks': 2, 229 | 230 | // require or disallow space before function opening parenthesis 231 | // http://eslint.org/docs/rules/space-before-function-paren 232 | 'space-before-function-paren': [2, { anonymous: 'always', named: 'never' }], 233 | 234 | // require or disallow spaces inside parentheses 235 | 'space-in-parens': [2, 'never'], 236 | 237 | // require spaces around operators 238 | 'space-infix-ops': 2, 239 | 240 | // Require or disallow spaces before/after unary operators 241 | 'space-unary-ops': 0, 242 | 243 | // require or disallow a space immediately following the // or /* in a comment 244 | 'spaced-comment': [2, 'always', { 245 | exceptions: ['-', '+'], 246 | markers: ['=', '!'] // space here to support sprockets directives 247 | }], 248 | 249 | // require regex literals to be wrapped in parentheses 250 | 'wrap-regex': 0 251 | } 252 | }; 253 | -------------------------------------------------------------------------------- /packages/eslint-config-airbnb-base/rules/variables.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | rules: { 3 | // enforce or disallow variable initializations at definition 4 | 'init-declarations': 0, 5 | 6 | // disallow the catch clause parameter name being the same as a variable in the outer scope 7 | 'no-catch-shadow': 0, 8 | 9 | // disallow deletion of variables 10 | 'no-delete-var': 2, 11 | 12 | // disallow labels that share a name with a variable 13 | 'no-label-var': 0, 14 | 15 | // disallow specific globals 16 | 'no-restricted-globals': 0, 17 | 18 | // disallow declaration of variables already declared in the outer scope 19 | 'no-shadow': 2, 20 | 21 | // disallow shadowing of names such as arguments 22 | 'no-shadow-restricted-names': 2, 23 | 24 | // disallow use of undeclared variables unless mentioned in a /*global */ block 25 | 'no-undef': 2, 26 | 27 | // disallow use of undefined when initializing variables 28 | 'no-undef-init': 0, 29 | 30 | // disallow use of undefined variable 31 | 'no-undefined': 0, 32 | 33 | // disallow declaration of variables that are not used in the code 34 | 'no-unused-vars': [2, { vars: 'local', args: 'after-used' }], 35 | 36 | // disallow use of variables before they are defined 37 | 'no-use-before-define': 2 38 | } 39 | }; 40 | -------------------------------------------------------------------------------- /packages/eslint-config-airbnb-base/test/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | // disabled because I find it tedious to write tests while following this 4 | // rule 5 | "no-shadow": 0, 6 | // tests uses `t` for tape 7 | "id-length": [2, {"min": 2, "properties": "never", "exceptions": ["t"]}] 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /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 | const index = require('../'); 6 | 7 | const files = { index }; 8 | 9 | fs.readdirSync(path.join(__dirname, '../rules')).forEach(name => { 10 | files[name] = require(`../rules/${name}`); // eslint-disable-line global-require 11 | }); 12 | 13 | Object.keys(files).forEach(name => { 14 | const config = files[name]; 15 | 16 | test(`${name}: does not reference react`, t => { 17 | t.plan(2); 18 | 19 | // scan plugins for react and fail if it is found 20 | const hasReactPlugin = Object.prototype.hasOwnProperty.call(config, 'plugins') && 21 | config.plugins.indexOf('react') !== -1; 22 | t.notOk(hasReactPlugin, 'there is no react plugin'); 23 | 24 | // scan rules for react/ and fail if any exist 25 | const reactRuleIds = Object.keys(config.rules) 26 | .filter(ruleId => ruleId.indexOf('react/') === 0); 27 | t.deepEquals(reactRuleIds, [], 'there are no react/ rules'); 28 | }); 29 | }); 30 | -------------------------------------------------------------------------------- /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/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 9.0.1 / 2016-05-08 2 | ================== 3 | - [patch] update `eslint-config-airbnb-base` to v3.0.1 4 | 5 | 9.0.0 / 2016-05-07 6 | ================== 7 | - [breaking] update `eslint-config-airbnb-base` to v3 8 | - [deps] update `eslint-find-rules`, `eslint-plugin-import`, `eslint-plugin-jsx-a11y` 9 | 10 | 8.0.0 / 2016-04-21 11 | ================== 12 | - [breaking] Migrate non-React rules to a separate linter config (`eslint-config-airbnb-base`) 13 | - [breaking] disallow empty methods 14 | - [breaking] disallow empty restructuring patterns 15 | - [breaking] enable `no-restricted-syntax` rule 16 | - [breaking] enable `global-require` rule 17 | - [breaking] [react] enable `react/jsx-curly-spacing` rule ([#693](https://github.com/airbnb/javascript/issues/693)) 18 | - [semver-minor] [react] Add `react/jsx-first-prop-new-line` rule 19 | - [semver-minor] [react] enable `jsx-equals-spacing` rule 20 | - [semver-minor] [react] enable `jsx-indent` rule 21 | - [semver-minor] enforce spacing inside single-line blocks 22 | - [semver-minor] enforce `no-underscore-dangle` 23 | - [semver-minor] Enable import/no-unresolved and import/export rules ([#825](https://github.com/airbnb/javascript/issues/825)) 24 | - [semver-patch] Enable `no-useless-concat` rule which `prefer-template` already covers 25 | - [semver-patch] Allow `== null` ([#542](https://github.com/airbnb/javascript/issues/542)) 26 | - [dev deps / peer deps] update `eslint`, `eslint-plugin-react`, `eslint-plugin-import` 27 | - [dev deps / peer deps] update `eslint-plugin-jsx-a11y` and rename rules ([#838](https://github.com/airbnb/javascript/issues/838)) 28 | - [refactor] [react] separate a11y rules to their own file 29 | - [refactor] Add missing disabled rules. 30 | - [tests] Add `eslint-find-rules` to prevent missing rules 31 | 32 | 7.0.0 / 2016-04-11 33 | ================== 34 | - [react] [breaking] Add accessibility rules to the React style guide + `eslint-plugin-a11y` 35 | - [breaking] enable `react/require-render-return` 36 | - [breaking] Add `no-dupe-class-members` rule + section ([#785](https://github.com/airbnb/javascript/issues/785)) 37 | - [breaking] error on debugger statements 38 | - [breaking] add `no-useless-escape` rule 39 | - [breaking] add `no-duplicate-imports` rule 40 | - [semver-minor] enable `jsx-pascal-case` rule 41 | - [deps] update `eslint`, `react` 42 | - [dev deps] update `eslint`, `eslint-plugin-react` 43 | 44 | 6.2.0 / 2016-03-22 45 | ================== 46 | - [new] Allow arrow functions in JSX props 47 | - [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)) 48 | - [dev deps] update `tape`, `eslint`, `eslint-plugin-react` 49 | - [peer deps] update `eslint`, `eslint-plugin-react` 50 | 51 | 6.1.0 / 2016-02-22 52 | ================== 53 | - [new] enable [`react/prefer-stateless-function`][react/prefer-stateless-function] 54 | - [dev deps] update `react-plugin-eslint`, `eslint`, `tape` 55 | 56 | 6.0.2 / 2016-02-22 57 | ================== 58 | - [fix] disable [`no-confusing-arrow`][no-confusing-arrow] due to an `eslint` bug ([#752](https://github.com/airbnb/javascript/issues/752)) 59 | 60 | 6.0.1 / 2016-02-21 61 | ================== 62 | - [fix] disable [`newline-per-chained-call`][newline-per-chained-call] due to an `eslint` bug ([#748](https://github.com/airbnb/javascript/issues/748)) 63 | 64 | 6.0.0 / 2016-02-21 65 | ================== 66 | - [breaking] enable [`array-callback-return`][array-callback-return] 67 | - [breaking] enable [`no-confusing-arrow`][no-confusing-arrow] 68 | - [breaking] enable [`no-new-symbol`][no-new-symbol] 69 | - [breaking] enable [`no-restricted-imports`][no-restricted-imports] 70 | - [breaking] enable [`no-useless-constructor`][no-useless-constructor] 71 | - [breaking] enable [`prefer-rest-params`][prefer-rest-params] 72 | - [breaking] enable [`template-curly-spacing`][template-curly-spacing] 73 | - [breaking] enable [`newline-per-chained-call`][newline-per-chained-call] 74 | - [breaking] enable [`one-var-declaration-per-line`][one-var-declaration-per-line] 75 | - [breaking] enable [`no-self-assign`][no-self-assign] 76 | - [breaking] enable [`no-whitespace-before-property`][no-whitespace-before-property] 77 | - [breaking] [react] enable [`react/jsx-space-before-closing`][react/jsx-space-before-closing] 78 | - [breaking] [react] enable `static-methods` at top of [`react/sort-comp`][react/sort-comp] 79 | - [breaking] [react] don't `ignoreTranspilerName` for [`react/display-name`][react/display-name] 80 | - [peer+dev deps] update `eslint`, `eslint-plugin-react` ([#730](https://github.com/airbnb/javascript/issues/730)) 81 | 82 | 5.0.1 / 2016-02-13 83 | ================== 84 | - [fix] `eslint` peerDep should not include breaking changes 85 | 86 | 5.0.0 / 2016-02-03 87 | ================== 88 | - [breaking] disallow unneeded ternary expressions 89 | - [breaking] Avoid lexical declarations in case/default clauses 90 | - [dev deps] update `babel-tape-runner`, `eslint-plugin-react`, `react`, `tape` 91 | 92 | 4.0.0 / 2016-01-22 93 | ================== 94 | - [breaking] require outer IIFE wrapping; flesh out guide section 95 | - [minor] Add missing [`arrow-body-style`][arrow-body-style], [`prefer-template`][prefer-template] rules ([#678](https://github.com/airbnb/javascript/issues/678)) 96 | - [minor] Add [`prefer-arrow-callback`][prefer-arrow-callback] to ES6 rules (to match the guide) ([#677](https://github.com/airbnb/javascript/issues/677)) 97 | - [Tests] run `npm run lint` as part of tests; fix errors 98 | - [Tests] use `parallelshell` to parallelize npm run-scripts 99 | 100 | 3.1.0 / 2016-01-07 101 | ================== 102 | - [minor] Allow multiple stateless components in a single file 103 | 104 | 3.0.2 / 2016-01-06 105 | ================== 106 | - [fix] Ignore URLs in [`max-len`][max-len] ([#664](https://github.com/airbnb/javascript/issues/664)) 107 | 108 | 3.0.1 / 2016-01-06 109 | ================== 110 | - [fix] because we use babel, keywords should not be quoted 111 | 112 | 3.0.0 / 2016-01-04 113 | ================== 114 | - [breaking] enable [`quote-props`][quote-props] rule ([#632](https://github.com/airbnb/javascript/issues/632)) 115 | - [breaking] Define a max line length of 100 characters ([#639](https://github.com/airbnb/javascript/issues/639)) 116 | - [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)) 117 | - [breaking] update best-practices config to prevent parameter object manipulation ([#627](https://github.com/airbnb/javascript/issues/627)) 118 | - [minor] Enable [`react/no-is-mounted`][react/no-is-mounted] rule (#635, #633) 119 | - [minor] Sort [`react/prefer-es6-class`][react/prefer-es6-class] alphabetically ([#634](https://github.com/airbnb/javascript/issues/634)) 120 | - [minor] enable [`react/prefer-es6-class`][react/prefer-es6-class] rule 121 | - Permit strict mode in "legacy" config 122 | - [react] add missing rules from `eslint-plugin-react` (enforcing where necessary) ([#581](https://github.com/airbnb/javascript/issues/581)) 123 | - [dev deps] update `eslint-plugin-react` 124 | 125 | 2.1.1 / 2015-12-15 126 | ================== 127 | - [fix] Remove deprecated [`react/jsx-quotes`][react/jsx-quotes] ([#622](https://github.com/airbnb/javascript/issues/622)) 128 | 129 | 2.1.0 / 2015-12-15 130 | ================== 131 | - [fix] use `require.resolve` to allow nested `extend`s ([#582](https://github.com/airbnb/javascript/issues/582)) 132 | - [new] enable [`object-shorthand`][object-shorthand] rule ([#621](https://github.com/airbnb/javascript/issues/621)) 133 | - [new] enable [`arrow-spacing`][arrow-spacing] rule ([#517](https://github.com/airbnb/javascript/issues/517)) 134 | - [docs] flesh out react rule defaults ([#618](https://github.com/airbnb/javascript/issues/618)) 135 | 136 | 2.0.0 / 2015-12-03 137 | ================== 138 | - [breaking] [`space-before-function-paren`][space-before-function-paren]: require function spacing: `function (` ([#605](https://github.com/airbnb/javascript/issues/605)) 139 | - [breaking] [`indent`][indent]: Fix switch statement indentation rule ([#606](https://github.com/airbnb/javascript/issues/606)) 140 | - [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)) 141 | - [breaking] [`object-curly-spacing`][object-curly-spacing]: require padding inside curly braces ([#594](https://github.com/airbnb/javascript/issues/594)) 142 | - [breaking] [`space-in-parens`][space-in-parens]: disallow spaces in parens ([#594](https://github.com/airbnb/javascript/issues/594)) 143 | 144 | 1.0.2 / 2015-11-25 145 | ================== 146 | - [breaking] [`no-multiple-empty-lines`][no-multiple-empty-lines]: only allow 1 blank line at EOF ([#578](https://github.com/airbnb/javascript/issues/578)) 147 | - [new] `restParams`: enable rest params ([#592](https://github.com/airbnb/javascript/issues/592)) 148 | 149 | 1.0.1 / 2015-11-25 150 | ================== 151 | - *erroneous publish* 152 | 153 | 1.0.0 / 2015-11-08 154 | ================== 155 | - require `eslint` `v1.0.0` or higher 156 | - remove `babel-eslint` dependency 157 | 158 | 0.1.1 / 2015-11-05 159 | ================== 160 | - remove [`id-length`][id-length] rule ([#569](https://github.com/airbnb/javascript/issues/569)) 161 | - enable [`no-mixed-spaces-and-tabs`][no-mixed-spaces-and-tabs] ([#539](https://github.com/airbnb/javascript/issues/539)) 162 | - enable [`no-const-assign`][no-const-assign] ([#560](https://github.com/airbnb/javascript/issues/560)) 163 | - enable [`space-before-keywords`][space-before-keywords] ([#554](https://github.com/airbnb/javascript/issues/554)) 164 | 165 | 0.1.0 / 2015-11-05 166 | ================== 167 | - switch to modular rules files courtesy the [eslint-config-default][ecd] project and [@taion][taion]. [PR][pr-modular] 168 | - export `eslint-config-airbnb/legacy` for ES5-only users. `eslint-config-airbnb/legacy` does not require the `babel-eslint` parser. [PR][pr-legacy] 169 | 170 | 0.0.9 / 2015-09-24 171 | ================== 172 | - add rule [`no-undef`][no-undef] 173 | - add rule [`id-length`][id-length] 174 | 175 | 0.0.8 / 2015-08-21 176 | ================== 177 | - now has a changelog 178 | - now is modular (see instructions above for with react and without react versions) 179 | 180 | 0.0.7 / 2015-07-30 181 | ================== 182 | - TODO: fill in 183 | 184 | 185 | [ecd]: https://github.com/walmartlabs/eslint-config-defaults 186 | [taion]: https://github.com/taion 187 | [pr-modular]: https://github.com/airbnb/javascript/pull/526 188 | [pr-legacy]: https://github.com/airbnb/javascript/pull/527 189 | 190 | [array-bracket-spacing]: http://eslint.org/docs/rules/array-bracket-spacing 191 | [array-callback-return]: http://eslint.org/docs/rules/array-callback-return 192 | [arrow-body-style]: http://eslint.org/docs/rules/arrow-body-style 193 | [arrow-spacing]: http://eslint.org/docs/rules/arrow-spacing 194 | [computed-property-spacing]: http://eslint.org/docs/rules/computed-property-spacing 195 | [id-length]: http://eslint.org/docs/rules/id-length 196 | [indent]: http://eslint.org/docs/rules/indent 197 | [max-len]: http://eslint.org/docs/rules/max-len 198 | [newline-per-chained-call]: http://eslint.org/docs/rules/newline-per-chained-call 199 | [no-confusing-arrow]: http://eslint.org/docs/rules/no-confusing-arrow 200 | [no-const-assign]: http://eslint.org/docs/rules/no-const-assign 201 | [no-mixed-spaces-and-tabs]: http://eslint.org/docs/rules/no-mixed-spaces-and-tabs 202 | [no-multiple-empty-lines]: http://eslint.org/docs/rules/no-multiple-empty-lines 203 | [no-new-symbol]: http://eslint.org/docs/rules/no-new-symbol 204 | [no-restricted-imports]: http://eslint.org/docs/rules/no-restricted-imports 205 | [no-self-assign]: http://eslint.org/docs/rules/no-self-assign 206 | [no-undef]: http://eslint.org/docs/rules/no-undef 207 | [no-useless-constructor]: http://eslint.org/docs/rules/no-useless-constructor 208 | [no-whitespace-before-property]: http://eslint.org/docs/rules/no-whitespace-before-property 209 | [object-curly-spacing]: http://eslint.org/docs/rules/object-curly-spacing 210 | [object-shorthand]: http://eslint.org/docs/rules/object-shorthand 211 | [one-var-declaration-per-line]: http://eslint.org/docs/rules/one-var-declaration-per-line 212 | [prefer-arrow-callback]: http://eslint.org/docs/rules/prefer-arrow-callback 213 | [prefer-rest-params]: http://eslint.org/docs/rules/prefer-rest-params 214 | [prefer-template]: http://eslint.org/docs/rules/prefer-template 215 | [quote-props]: http://eslint.org/docs/rules/quote-props 216 | [space-before-function-paren]: http://eslint.org/docs/rules/space-before-function-paren 217 | [space-before-keywords]: http://eslint.org/docs/rules/space-before-keywords 218 | [space-in-parens]: http://eslint.org/docs/rules/space-in-parens 219 | [template-curly-spacing]: http://eslint.org/docs/rules/template-curly-spacing 220 | 221 | [react/jsx-space-before-closing]: https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-space-before-closing.md 222 | [react/sort-comp]: https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/sort-comp.md 223 | [react/display-name]: https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/display-name.md 224 | [react/jsx-no-bind]: https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-bind.md 225 | [react/no-is-mounted]: https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-is-mounted.md 226 | [react/prefer-es6-class]: https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/prefer-es6-class.md 227 | [react/jsx-quotes]: https://github.com/yannickcr/eslint-plugin-react/blob/f817e37beddddc84b4788969f07c524fa7f0823b/docs/rules/jsx-quotes.md 228 | [react/prefer-stateless-function]: https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/prefer-stateless-function.md 229 | -------------------------------------------------------------------------------- /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`. 14 | 15 | 1. `npm install --save-dev eslint-config-airbnb eslint-plugin-import eslint-plugin-react eslint-plugin-jsx-a11y eslint` 16 | 2. add `"extends": "airbnb"` to your .eslintrc 17 | 18 | ### eslint-config-airbnb/base 19 | 20 | This entry point is deprecated. See [eslint-config-airbnb-base](https://npmjs.com/eslint-config-airbnb-base). 21 | 22 | ### eslint-config-airbnb/legacy 23 | 24 | This entry point is deprecated. See [eslint-config-airbnb-base](https://npmjs.com/eslint-config-airbnb-base). 25 | 26 | See [Airbnb's Javascript styleguide](https://github.com/airbnb/javascript) and 27 | the [ESlint config docs](http://eslint.org/docs/user-guide/configuring#extending-configuration-files) 28 | for more information. 29 | 30 | ## Improving this config 31 | 32 | 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? 33 | 34 | You can run tests with `npm test`. 35 | 36 | You can make sure this module lints with itself using `npm run lint`. 37 | -------------------------------------------------------------------------------- /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": "9.0.1", 4 | "description": "Airbnb's ESLint config, following our styleguide", 5 | "main": "index.js", 6 | "scripts": { 7 | "lint": "eslint .", 8 | "tests-only": "babel-tape-runner ./test/test-*.js", 9 | "pretest": "eslint-find-rules --unused", 10 | "test": "npm run --silent lint && npm run --silent tests-only", 11 | "travis": "cd ../eslint-config-airbnb-base && npm link && cd - && npm link eslint-config-airbnb-base && npm run --silent test ; npm unlink eslint-config-airbnb-base >/dev/null &" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "https://github.com/airbnb/javascript" 16 | }, 17 | "keywords": [ 18 | "eslint", 19 | "eslintconfig", 20 | "config", 21 | "airbnb", 22 | "javascript", 23 | "styleguide" 24 | ], 25 | "author": "Jake Teton-Landis (https://twitter.com/@jitl)", 26 | "contributors": [ 27 | { 28 | "name": "Jake Teton-Landis", 29 | "url": "https://twitter.com/jitl" 30 | }, 31 | { 32 | "name": "Jordan Harband", 33 | "email": "ljharb@gmail.com", 34 | "url": "http://ljharb.codes" 35 | }, 36 | { 37 | "name": "Harrison Shoff", 38 | "url": "https://twitter.com/hshoff" 39 | } 40 | ], 41 | "license": "MIT", 42 | "bugs": { 43 | "url": "https://github.com/airbnb/javascript/issues" 44 | }, 45 | "homepage": "https://github.com/airbnb/javascript", 46 | "dependencies": { 47 | "eslint-config-airbnb-base": "^3.0.1" 48 | }, 49 | "devDependencies": { 50 | "babel-tape-runner": "^1.3.1", 51 | "eslint": "^2.9.0", 52 | "eslint-find-rules": "^1.9.2", 53 | "eslint-plugin-import": "^1.8.0", 54 | "eslint-plugin-jsx-a11y": "^1.2.0", 55 | "eslint-plugin-react": "^5.1.1", 56 | "react": "*", 57 | "tape": "^4.5.1" 58 | }, 59 | "peerDependencies": { 60 | "eslint": "^2.9.0", 61 | "eslint-plugin-jsx-a11y": "^1.2.0", 62 | "eslint-plugin-import": "^1.8.0", 63 | "eslint-plugin-react": "^5.1.1" 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /packages/eslint-config-airbnb/rules/react-a11y.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: [ 3 | 'jsx-a11y', 4 | 'react' 5 | ], 6 | ecmaFeatures: { 7 | jsx: true 8 | }, 9 | rules: { 10 | // Require ARIA roles to be valid and non-abstract 11 | // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/aria-role.md 12 | 'jsx-a11y/aria-role': 2, 13 | 14 | // Enforce all aria-* props are valid. 15 | // TODO: enable 16 | // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/aria-props.md 17 | 'jsx-a11y/aria-props': 0, 18 | 19 | // Enforce ARIA state and property values are valid. 20 | // TODO: enable 21 | // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/aria-proptypes.md 22 | 'jsx-a11y/aria-proptypes': 0, 23 | 24 | // Enforce that elements that do not support ARIA roles, states, and 25 | // properties do not have those attributes. 26 | // TODO: enable 27 | // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/aria-unsupported-elements.md 28 | 'jsx-a11y/aria-unsupported-elements': 0, 29 | 30 | // disallow href "#" 31 | // TODO: enable 32 | // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/href-no-hash.md 33 | 'jsx-a11y/href-no-hash': 0, 34 | 35 | // Require to have a non-empty `alt` prop, or role="presentation" 36 | // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/img-has-alt.md 37 | 'jsx-a11y/img-has-alt': 2, 38 | 39 | // Prevent img alt text from containing redundant words like "image", "picture", or "photo" 40 | // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/img-redundant-alt.md 41 | 'jsx-a11y/img-redundant-alt': 2, 42 | 43 | // require that JSX labels use "htmlFor" 44 | // TODO: enable 45 | // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/label-has-for.md 46 | 'jsx-a11y/label-has-for': 0, 47 | 48 | // require that mouseover/out come with focus/blur, for keyboard-only users 49 | // TODO: enable? 50 | // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/mouse-events-have-key-events.md 51 | 'jsx-a11y/mouse-events-have-key-events': 0, 52 | 53 | // Prevent use of `accessKey` 54 | // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/no-access-key.md 55 | 'jsx-a11y/no-access-key': 2, 56 | 57 | // require onBlur instead of onChange 58 | // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/no-onchange.md 59 | 'jsx-a11y/no-onchange': 0, 60 | 61 | // Enforce that elements with onClick handlers must be focusable. 62 | // TODO: evaluate 63 | // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/onclick-has-focus.md 64 | 'jsx-a11y/onclick-has-focus': 0, 65 | 66 | // require things with onClick to have an aria role 67 | // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/onclick-has-role.md 68 | 'jsx-a11y/onclick-has-role': 0, 69 | 70 | // Enforce that elements with ARIA roles must have all required attributes 71 | // for that role. 72 | // TODO: enable 73 | // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/role-has-required-aria-props.md 74 | 'jsx-a11y/role-has-required-aria-props': 0, 75 | 76 | // Enforce that elements with explicit or implicit roles defined contain 77 | // only aria-* properties supported by that role. 78 | // TODO: enable 79 | // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/role-supports-aria-props.md 80 | 'jsx-a11y/role-supports-aria-props': 0, 81 | 82 | // Enforce tabIndex value is not greater than zero. 83 | // TODO: evaluate 84 | // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/tabindex-no-positive.md 85 | 'jsx-a11y/tabindex-no-positive': 0, 86 | }, 87 | }; 88 | -------------------------------------------------------------------------------- /packages/eslint-config-airbnb/rules/react.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: [ 3 | 'react' 4 | ], 5 | parserOptions: { 6 | ecmaFeatures: { 7 | jsx: true, 8 | }, 9 | }, 10 | ecmaFeatures: { 11 | jsx: true 12 | }, 13 | 14 | // View link below for react rules documentation 15 | // https://github.com/yannickcr/eslint-plugin-react#list-of-supported-rules 16 | rules: { 17 | // specify whether double or single quotes should be used in JSX attributes 18 | // http://eslint.org/docs/rules/jsx-quotes 19 | 'jsx-quotes': [2, 'prefer-double'], 20 | 21 | // Prevent missing displayName in a React component definition 22 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/display-name.md 23 | 'react/display-name': [0, { ignoreTranspilerName: false }], 24 | 25 | // Forbid certain propTypes (any, array, object) 26 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/forbid-prop-types.md 27 | 'react/forbid-prop-types': [0, { forbid: ['any', 'array', 'object'] }], 28 | 29 | // Enforce boolean attributes notation in JSX 30 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-boolean-value.md 31 | 'react/jsx-boolean-value': [2, 'never'], 32 | 33 | // Validate closing bracket location in JSX 34 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-closing-bracket-location.md 35 | 'react/jsx-closing-bracket-location': [2, 'line-aligned'], 36 | 37 | // Enforce or disallow spaces inside of curly braces in JSX attributes 38 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-curly-spacing.md 39 | 'react/jsx-curly-spacing': [2, 'never', { allowMultiline: true }], 40 | 41 | // Enforce event handler naming conventions in JSX 42 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-handler-names.md 43 | 'react/jsx-handler-names': [0, { 44 | eventHandlerPrefix: 'handle', 45 | eventHandlerPropPrefix: 'on', 46 | }], 47 | 48 | // Validate props indentation in JSX 49 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-indent-props.md 50 | 'react/jsx-indent-props': [2, 2], 51 | 52 | // Validate JSX has key prop when in array or iterator 53 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-key.md 54 | 'react/jsx-key': 0, 55 | 56 | // Limit maximum of props on a single line in JSX 57 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-max-props-per-line.md 58 | 'react/jsx-max-props-per-line': [0, { maximum: 1 }], 59 | 60 | // Prevent usage of .bind() in JSX props 61 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-bind.md 62 | 'react/jsx-no-bind': [2, { 63 | ignoreRefs: true, 64 | allowArrowFunctions: true, 65 | allowBind: false, 66 | }], 67 | 68 | // Prevent duplicate props in JSX 69 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-duplicate-props.md 70 | 'react/jsx-no-duplicate-props': [0, { ignoreCase: false }], 71 | 72 | // Prevent usage of unwrapped JSX strings 73 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-literals.md 74 | 'react/jsx-no-literals': 0, 75 | 76 | // Disallow undeclared variables in JSX 77 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-undef.md 78 | 'react/jsx-no-undef': 2, 79 | 80 | // Enforce PascalCase for user-defined JSX components 81 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-pascal-case.md 82 | 'react/jsx-pascal-case': [2, { 83 | allowAllCaps: true, 84 | ignore: [], 85 | }], 86 | 87 | // Enforce propTypes declarations alphabetical sorting 88 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/sort-prop-types.md 89 | 'react/sort-prop-types': [0, { 90 | ignoreCase: false, 91 | callbacksLast: false, 92 | }], 93 | 94 | // deprecated in favor of react/jsx-sort-props 95 | 'react/jsx-sort-prop-types': 0, 96 | 97 | // Enforce props alphabetical sorting 98 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-sort-props.md 99 | 'react/jsx-sort-props': [0, { 100 | ignoreCase: false, 101 | callbacksLast: false, 102 | }], 103 | 104 | // Prevent React to be incorrectly marked as unused 105 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-uses-react.md 106 | 'react/jsx-uses-react': [2, { pragma: 'React' }], 107 | 108 | // Prevent variables used in JSX to be incorrectly marked as unused 109 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-uses-vars.md 110 | 'react/jsx-uses-vars': 2, 111 | 112 | // Prevent usage of dangerous JSX properties 113 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-danger.md 114 | 'react/no-danger': 0, 115 | 116 | // Prevent usage of deprecated methods 117 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-deprecated.md 118 | 'react/no-deprecated': [1, { react: '0.14.0' }], 119 | 120 | // Prevent usage of setState in componentDidMount 121 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-did-mount-set-state.md 122 | 'react/no-did-mount-set-state': [2, 'allow-in-func'], 123 | 124 | // Prevent usage of setState in componentDidUpdate 125 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-did-update-set-state.md 126 | 'react/no-did-update-set-state': [2, 'allow-in-func'], 127 | 128 | // Prevent direct mutation of this.state 129 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-direct-mutation-state.md 130 | 'react/no-direct-mutation-state': 0, 131 | 132 | // Prevent usage of isMounted 133 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-is-mounted.md 134 | 'react/no-is-mounted': 2, 135 | 136 | // Prevent multiple component definition per file 137 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-multi-comp.md 138 | 'react/no-multi-comp': [2, { ignoreStateless: true }], 139 | 140 | // Prevent usage of setState 141 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-set-state.md 142 | 'react/no-set-state': 0, 143 | 144 | // Prevent using string references 145 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-string-refs.md 146 | 'react/no-string-refs': 0, 147 | 148 | // Prevent usage of unknown DOM property 149 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-unknown-property.md 150 | 'react/no-unknown-property': 2, 151 | 152 | // Require ES6 class declarations over React.createClass 153 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/prefer-es6-class.md 154 | 'react/prefer-es6-class': [2, 'always'], 155 | 156 | // Require stateless functions when not using lifecycle methods, setState or ref 157 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/prefer-stateless-function.md 158 | 'react/prefer-stateless-function': 2, 159 | 160 | // Prevent missing props validation in a React component definition 161 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/prop-types.md 162 | 'react/prop-types': [2, { ignore: [], customValidators: [] }], 163 | 164 | // Prevent missing React when using JSX 165 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/react-in-jsx-scope.md 166 | 'react/react-in-jsx-scope': 2, 167 | 168 | // Restrict file extensions that may be required 169 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/require-extension.md 170 | 'react/require-extension': [0, { extensions: ['.jsx'] }], 171 | 172 | // Require render() methods to return something 173 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/require-render-return.md 174 | 'react/require-render-return': 2, 175 | 176 | // Prevent extra closing tags for components without children 177 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/self-closing-comp.md 178 | 'react/self-closing-comp': 2, 179 | 180 | // Enforce spaces before the closing bracket of self-closing JSX elements 181 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-space-before-closing.md 182 | 'react/jsx-space-before-closing': [2, 'always'], 183 | 184 | // Enforce component methods order 185 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/sort-comp.md 186 | 'react/sort-comp': [2, { 187 | order: [ 188 | 'static-methods', 189 | 'lifecycle', 190 | '/^on.+$/', 191 | '/^(get|set)(?!(InitialState$|DefaultProps$|ChildContext$)).+$/', 192 | 'everything-else', 193 | '/^render.+$/', 194 | 'render' 195 | ], 196 | }], 197 | 198 | // Prevent missing parentheses around multilines JSX 199 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/wrap-multilines.md 200 | 'react/wrap-multilines': [2, { 201 | declaration: true, 202 | assignment: true, 203 | return: true 204 | }], 205 | 206 | // Require that the first prop in a JSX element be on a new line when the element is multiline 207 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-first-prop-new-line.md 208 | 'react/jsx-first-prop-new-line': [2, 'multiline'], 209 | 210 | // enforce spacing around jsx equals signs 211 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-equals-spacing.md 212 | 'react/jsx-equals-spacing': [2, 'never'], 213 | 214 | // enforce JSX indentation 215 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-indent.md 216 | 'react/jsx-indent': [2, 2], 217 | 218 | // disallow target="_blank" on links 219 | // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-target-blank.md 220 | // TODO: enable 221 | 'react/jsx-no-target-blank': 0 222 | }, 223 | 224 | settings: { 225 | 'import/resolver': { 226 | node: { 227 | extensions: ['.js', '.jsx', '.json'] 228 | } 229 | }, 230 | react: { 231 | pragma: 'React', 232 | version: '0.14' 233 | }, 234 | } 235 | }; 236 | -------------------------------------------------------------------------------- /packages/eslint-config-airbnb/test/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | // disabled because I find it tedious to write tests while following this 4 | // rule 5 | "no-shadow": 0, 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 | files[name] = require(`../rules/${name}`); // eslint-disable-line global-require 15 | }); 16 | 17 | Object.keys(files).forEach(name => { 18 | const config = files[name]; 19 | 20 | test(`${name}: does not reference react`, t => { 21 | t.plan(2); 22 | 23 | // scan plugins for react and fail if it is found 24 | const hasReactPlugin = Object.prototype.hasOwnProperty.call(config, 'plugins') && 25 | config.plugins.indexOf('react') !== -1; 26 | t.notOk(hasReactPlugin, 'there is no react plugin'); 27 | 28 | // scan rules for react/ and fail if any exist 29 | const reactRuleIds = Object.keys(config.rules) 30 | .filter(ruleId => ruleId.indexOf('react/') === 0); 31 | t.deepEquals(reactRuleIds, [], 'there are no react/ rules'); 32 | }); 33 | }); 34 | -------------------------------------------------------------------------------- /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 | // This rule fails when executing on text. 12 | rules: { indent: 0 }, 13 | }); 14 | 15 | function lint(text) { 16 | // @see http://eslint.org/docs/developer-guide/nodejs-api.html#executeonfiles 17 | // @see http://eslint.org/docs/developer-guide/nodejs-api.html#executeontext 18 | const linter = cli.executeOnText(text); 19 | return linter.results[0]; 20 | } 21 | 22 | function wrapComponent(body) { 23 | return ` 24 | import React from 'react'; 25 | export default class MyComponent extends React.Component { 26 | /* eslint no-empty-function: 0 */ 27 | ${body} 28 | } 29 | `; 30 | } 31 | 32 | test('validate react prop order', (t) => { 33 | t.test('make sure our eslintrc has React and JSX linting dependencies', (t) => { 34 | t.plan(2); 35 | t.deepEqual(reactRules.plugins, ['react']); 36 | t.deepEqual(reactA11yRules.plugins, ['jsx-a11y', 'react']); 37 | }); 38 | 39 | t.test('passes a good component', (t) => { 40 | t.plan(3); 41 | const result = lint(wrapComponent(` 42 | componentWillMount() {} 43 | componentDidMount() {} 44 | setFoo() {} 45 | getFoo() {} 46 | setBar() {} 47 | someMethod() {} 48 | renderDogs() {} 49 | render() { return
    ; } 50 | `)); 51 | 52 | t.notOk(result.warningCount, 'no warnings'); 53 | t.notOk(result.errorCount, 'no errors'); 54 | t.deepEquals(result.messages, [], 'no messages in results'); 55 | }); 56 | 57 | t.test('order: when random method is first', t => { 58 | t.plan(2); 59 | const result = lint(wrapComponent(` 60 | someMethod() {} 61 | componentWillMount() {} 62 | componentDidMount() {} 63 | setFoo() {} 64 | getFoo() {} 65 | setBar() {} 66 | renderDogs() {} 67 | render() { return
    ; } 68 | `)); 69 | 70 | t.ok(result.errorCount, 'fails'); 71 | t.equal(result.messages[0].ruleId, 'react/sort-comp', 'fails due to sort'); 72 | }); 73 | 74 | t.test('order: when random method after lifecycle methods', t => { 75 | t.plan(2); 76 | const result = lint(wrapComponent(` 77 | componentWillMount() {} 78 | componentDidMount() {} 79 | someMethod() {} 80 | setFoo() {} 81 | getFoo() {} 82 | setBar() {} 83 | renderDogs() {} 84 | render() { return
    ; } 85 | `)); 86 | 87 | t.ok(result.errorCount, 'fails'); 88 | t.equal(result.messages[0].ruleId, 'react/sort-comp', 'fails due to sort'); 89 | }); 90 | }); 91 | -------------------------------------------------------------------------------- /react/README.md: -------------------------------------------------------------------------------- 1 | # Airbnb React/JSX 编码规范 2 | 3 | *算是最合理的React/JSX编码规范之一了* 4 | 5 | 此编码规范主要基于目前流行的JavaScript标准,尽管某些其他约定(如async/await,静态class属性)可能在不同的项目中被引入或者被禁用。目前的状态是任何stage-3之前的规范都不包括也不推荐使用。 6 | 7 | ## 内容目录 8 | 9 | 1. [基本规范](#basic-rules-基本规范) 10 | 1. [Class vs React.createClass vs stateless](#创建模块) 11 | 1. [Mixins](#mixins) 12 | 1. [命名](#naming-命名) 13 | 1. [声明模块](#declaration-声明模块) 14 | 1. [代码对齐](#alignment-代码对齐) 15 | 1. [单引号还是双引号](#quotes-单引号还是双引号) 16 | 1. [空格](#spacing-空格) 17 | 1. [属性](#props-属性) 18 | 1. [Refs引用](#refs) 19 | 1. [括号](#parentheses-括号) 20 | 1. [标签](#tags-标签) 21 | 1. [函数/方法](#methods-函数) 22 | 1. [模块生命周期](#ordering-react-模块生命周期) 23 | 1. [isMounted](#ismounted) 24 | 25 | ## Basic Rules 基本规范 26 | 27 | - 每个文件只写一个模块. 28 | - 但是多个[无状态模块](https://facebook.github.io/react/docs/reusable-components.html#stateless-functions)可以放在单个文件中. eslint: [`react/no-multi-comp`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-multi-comp.md#ignorestateless). 29 | - 推荐使用JSX语法. 30 | - 不要使用 `React.createElement`,除非从一个非JSX的文件中初始化你的app. 31 | 32 | ## 创建模块 33 | Class vs React.createClass vs stateless 34 | 35 | - 如果你的模块有内部状态或者是`refs`, 推荐使用 `class extends React.Component` 而不是 `React.createClass`. 36 | 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) 37 | 38 | ```jsx 39 | // bad 40 | const Listing = React.createClass({ 41 | // ... 42 | render() { 43 | return
    {this.state.hello}
    ; 44 | } 45 | }); 46 | 47 | // good 48 | class Listing extends React.Component { 49 | // ... 50 | render() { 51 | return
    {this.state.hello}
    ; 52 | } 53 | } 54 | ``` 55 | 56 | 如果你的模块没有状态或是没有引用`refs`, 推荐使用普通函数(非箭头函数)而不是类: 57 | 58 | ```jsx 59 | // bad 60 | class Listing extends React.Component { 61 | render() { 62 | return
    {this.props.hello}
    ; 63 | } 64 | } 65 | 66 | // bad (relying on function name inference is discouraged) 67 | const Listing = ({ hello }) => ( 68 |
    {hello}
    69 | ); 70 | 71 | // good 72 | function Listing({ hello }) { 73 | return
    {hello}
    ; 74 | } 75 | ``` 76 | 77 | ## Mixins 78 | 79 | - [不要使用 mixins](https://facebook.github.io/react/blog/2016/07/13/mixins-considered-harmful.html). 80 | 81 | > 为什么? Mixins 会增加隐式的依赖,导致命名冲突,并且会以雪球式增加复杂度。在大多数情况下Mixins可以被更好的方法替代,如:组件化,高阶组件,工具模块等。 82 | 83 | ## Naming 命名 84 | 85 | - **扩展名**: React模块使用 `.jsx` 扩展名. 86 | 87 | - **文件名**: 文件名使用帕斯卡命名. 如, `ReservationCard.jsx`. 88 | 89 | - **引用命名**: React模块名使用帕斯卡命名,实例使用骆驼式命名. eslint: [`react/jsx-pascal-case`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-pascal-case.md) 90 | 91 | ```jsx 92 | // bad 93 | import reservationCard from './ReservationCard'; 94 | 95 | // good 96 | import ReservationCard from './ReservationCard'; 97 | 98 | // bad 99 | const ReservationItem = ; 100 | 101 | // good 102 | const reservationItem = ; 103 | ``` 104 | 105 | - **模块命名**: 模块使用当前文件名一样的名称. 比如 `ReservationCard.jsx` 应该包含名为 `ReservationCard`的模块. 但是,如果整个文件夹是一个模块,使用 `index.js`作为入口文件,然后直接使用 `index.js` 或者文件夹名作为模块的名称: 106 | 107 | ```jsx 108 | // bad 109 | import Footer from './Footer/Footer'; 110 | 111 | // bad 112 | import Footer from './Footer/index'; 113 | 114 | // good 115 | import Footer from './Footer'; 116 | ``` 117 | - **高阶模块命名**: 对于生成一个新的模块,其中的模块名 `displayName` 应该为高阶模块名和传入模块名的组合. 例如, 高阶模块 `withFoo()`, 当传入一个 `Bar` 模块的时候, 生成的模块名 `displayName` 应该为 `withFoo(Bar)`. 118 | 119 | > 为什么?一个模块的 `displayName` 可能会在开发者工具或者错误信息中使用到,因此有一个能清楚的表达这层关系的值能帮助我们更好的理解模块发生了什么,更好的Debug. 120 | 121 | ```jsx 122 | // bad 123 | export default function withFoo(WrappedComponent) { 124 | return function WithFoo(props) { 125 | return ; 126 | } 127 | } 128 | 129 | // good 130 | export default function withFoo(WrappedComponent) { 131 | function WithFoo(props) { 132 | return ; 133 | } 134 | 135 | const wrappedComponentName = WrappedComponent.displayName 136 | || WrappedComponent.name 137 | || 'Component'; 138 | 139 | WithFoo.displayName = `withFoo(${wrappedComponentName})`; 140 | return WithFoo; 141 | } 142 | ``` 143 | 144 | - **属性命名**: 避免使用DOM相关的属性来用作其他的用途。 145 | 146 | > 为什么?对于`style` 和 `className`这样的属性名,我们都会默认它们代表一些特殊的含义,如元素的样式,CSS class的名称。在你的应用中使用这些属性来表示其他的含义会使你的代码更难阅读,更难维护,并且可能会引起bug。 147 | 148 | ```jsx 149 | // bad 150 | 151 | 152 | // good 153 | 154 | ``` 155 | 156 | ## Declaration 声明模块 157 | 158 | - 不要使用 `displayName` 来命名React模块,而是使用引用来命名模块, 如 class 名称. 159 | 160 | ```jsx 161 | // bad 162 | export default React.createClass({ 163 | displayName: 'ReservationCard', 164 | // stuff goes here 165 | }); 166 | 167 | // good 168 | export default class ReservationCard extends React.Component { 169 | } 170 | ``` 171 | 172 | ## Alignment 代码对齐 173 | 174 | - 遵循以下的JSX语法缩进/格式. eslint: [`react/jsx-closing-bracket-location`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-closing-bracket-location.md) [`react/jsx-closing-tag-location`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-closing-tag-location.md) 175 | 176 | ```jsx 177 | // bad 178 | 180 | 181 | // good, 有多行属性的话, 新建一行关闭标签 182 | 186 | 187 | // 若能在一行中显示, 直接写成一行 188 | 189 | 190 | // 子元素按照常规方式缩进 191 | 195 | 196 | 197 | ``` 198 | 199 | ## Quotes 单引号还是双引号 200 | 201 | - 对于JSX属性值总是使用双引号(`"`), 其他均使用单引号(`'`). eslint: [`jsx-quotes`](http://eslint.org/docs/rules/jsx-quotes) 202 | 203 | > 为什么? HTML属性也是用双引号, 因此JSX的属性也遵循此约定. 204 | 205 | ```jsx 206 | // bad 207 | 208 | 209 | // good 210 | 211 | 212 | // bad 213 | 214 | 215 | // good 216 | 217 | ``` 218 | 219 | ## Spacing 空格 220 | 221 | - 总是在自动关闭的标签前加一个空格,正常情况下也不需要换行. 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) 222 | 223 | ```jsx 224 | // bad 225 | 226 | 227 | // very bad 228 | 229 | 230 | // bad 231 | 233 | 234 | // good 235 | 236 | ``` 237 | 238 | - 不要在JSX `{}` 引用括号里两边加空格. eslint: [`react/jsx-curly-spacing`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-curly-spacing.md) 239 | 240 | ```jsx 241 | // bad 242 | 243 | 244 | // good 245 | 246 | ``` 247 | 248 | ## Props 属性 249 | 250 | - JSX属性名使用骆驼式风格`camelCase`. 251 | 252 | ```jsx 253 | // bad 254 | 258 | 259 | // good 260 | 264 | ``` 265 | 266 | - 如果属性值为 `true`, 可以直接省略. eslint: [`react/jsx-boolean-value`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-boolean-value.md) 267 | 268 | ```jsx 269 | // bad 270 |