├── .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 | [](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 = '
';
240 |
241 | for (i = 0; i < length; i++) {
242 | items += '- ' + messages[i].message + '
';
243 | }
244 |
245 | return 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 | -  **Brazilian Portuguese**: [armoucar/javascript-style-guide](https://github.com/armoucar/javascript-style-guide)
1689 | -  **Bulgarian**: [borislavvv/javascript](https://github.com/borislavvv/javascript)
1690 | -  **Catalan**: [fpmweb/javascript-style-guide](https://github.com/fpmweb/javascript-style-guide)
1691 | -  **Chinese(Traditional)**: [jigsawye/javascript](https://github.com/jigsawye/javascript)
1692 | -  **Chinese(Simplified)**: [sivan/javascript-style-guide](https://github.com/sivan/javascript-style-guide)
1693 | -  **French**: [nmussy/javascript-style-guide](https://github.com/nmussy/javascript-style-guide)
1694 | -  **German**: [timofurrer/javascript-style-guide](https://github.com/timofurrer/javascript-style-guide)
1695 | -  **Italian**: [sinkswim/javascript-style-guide](https://github.com/sinkswim/javascript-style-guide)
1696 | -  **Japanese**: [mitsuruog/javacript-style-guide](https://github.com/mitsuruog/javacript-style-guide)
1697 | -  **Korean**: [tipjs/javascript-style-guide](https://github.com/tipjs/javascript-style-guide)
1698 | -  **Polish**: [mjurczyk/javascript](https://github.com/mjurczyk/javascript)
1699 | -  **Russian**: [uprock/javascript](https://github.com/uprock/javascript)
1700 | -  **Spanish**: [paolocarrasco/javascript-style-guide](https://github.com/paolocarrasco/javascript-style-guide)
1701 | -  **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 | [](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 | [](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 |
273 |
274 | // good
275 |
278 |
279 | // good
280 |
281 | ```
282 |
283 | - `
` 标签总是添加 `alt` 属性. 如果图片以presentation(感觉是以类似PPT方式显示?)方式显示,`alt` 可为空, 或者`
` 要包含`role="presentation"`. eslint: [`jsx-a11y/alt-text`](https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/alt-text.md)
284 |
285 | ```jsx
286 | // bad
287 |
288 |
289 | // good
290 |
291 |
292 | // good
293 |
294 |
295 | // good
296 |
297 | ```
298 |
299 | - 不要在 `alt` 值里使用如 "image", "photo", or "picture"包括图片含义这样的词, 中文也一样. eslint: [`jsx-a11y/img-redundant-alt`](https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/img-redundant-alt.md)
300 |
301 | > 为什么? 屏幕助读器已经把 `img` 标签标注为图片了, 所以没有必要再在 `alt` 里说明了.
302 |
303 | ```jsx
304 | // bad
305 |
306 |
307 | // good
308 |
309 | ```
310 |
311 | - 使用有效正确的 aria `role`属性值 [ARIA roles](https://www.w3.org/TR/wai-aria/roles#usage_intro). eslint: [`jsx-a11y/aria-role`](https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/aria-role.md)
312 |
313 | ```jsx
314 | // bad - not an ARIA role
315 |
316 |
317 | // bad - abstract ARIA role
318 |
319 |
320 | // good
321 |
322 | ```
323 |
324 | - 不要在标签上使用 `accessKey` 属性. eslint: [`jsx-a11y/no-access-key`](https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/no-access-key.md)
325 |
326 | > 为什么? 屏幕助读器在键盘快捷键与键盘命令时造成的不统一性会导致阅读性更加复杂.
327 |
328 | ```jsx
329 | // bad
330 |
331 |
332 | // good
333 |
334 | ```
335 | - 避免使用数组的index来作为属性`key`的值,推荐使用唯一ID. ([为什么?](https://medium.com/@robinpokorny/index-as-a-key-is-an-anti-pattern-e0349aece318))
336 |
337 | ```jsx
338 | // bad
339 | {todos.map((todo, index) =>
340 |
344 | )}
345 |
346 | // good
347 | {todos.map(todo => (
348 |
352 | ))}
353 | ```
354 |
355 | - 对于所有非必须的属性,总是手动去定义`defaultProps`属性.
356 |
357 | > 为什么? propTypes 可以作为模块的文档说明, 并且声明 defaultProps 的话意味着阅读代码的人不需要去假设一些默认值。更重要的是, 显示的声明默认属性可以让你的模块跳过属性类型的检查.
358 |
359 | ```jsx
360 | // bad
361 | function SFC({ foo, bar, children }) {
362 | return {foo}{bar}{children}
;
363 | }
364 | SFC.propTypes = {
365 | foo: PropTypes.number.isRequired,
366 | bar: PropTypes.string,
367 | children: PropTypes.node,
368 | };
369 |
370 | // good
371 | function SFC({ foo, bar, children }) {
372 | return {foo}{bar}{children}
;
373 | }
374 | SFC.propTypes = {
375 | foo: PropTypes.number.isRequired,
376 | bar: PropTypes.string,
377 | children: PropTypes.node,
378 | };
379 | SFC.defaultProps = {
380 | bar: '',
381 | children: null,
382 | };
383 | ```
384 |
385 | - 尽可能少地使用扩展运算符
386 |
387 | > 为什么? 除非你很想传递一些不必要的属性。对于React v15.6.1和更早的版本,你可以[给DOM传递一些无效的HTML属性](https://doc.react-china.org/blog/2017/09/08/dom-attributes-in-react-16.html)
388 |
389 | 例外情况:
390 |
391 | - 使用了变量提升的高阶组件
392 |
393 | ```jsx
394 | function HOC(WrappedComponent) {
395 | return class Proxy extends React.Component {
396 | Proxy.propTypes = {
397 | text: PropTypes.string,
398 | isLoading: PropTypes.bool
399 | };
400 |
401 | render() {
402 | return
403 | }
404 | }
405 | }
406 | ```
407 |
408 | - 只有在清楚明白扩展对象时才使用扩展运算符。这非常有用尤其是在使用Mocha测试组件的时候。
409 |
410 | ```jsx
411 | export default function Foo {
412 | const props = {
413 | text: '',
414 | isPublished: false
415 | }
416 |
417 | return ();
418 | }
419 | ```
420 |
421 | 特别提醒:尽可能地筛选出不必要的属性。同时,使用[prop-types-exact](https://www.npmjs.com/package/prop-types-exact)来预防问题出现。
422 |
423 | ```jsx
424 | // good
425 | render() {
426 | const { irrelevantProp, ...relevantProps } = this.props;
427 | return
428 | }
429 |
430 | // bad
431 | render() {
432 | const { irrelevantProp, ...relevantProps } = this.props;
433 | return
434 | }
435 | ```
436 |
437 |
438 | ## Refs
439 |
440 | - 总是在Refs里使用回调函数. eslint: [`react/no-string-refs`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-string-refs.md)
441 |
442 | ```jsx
443 | // bad
444 |
447 |
448 | // good
449 | { this.myRef = ref; }}
451 | />
452 | ```
453 |
454 |
455 | ## Parentheses 括号
456 |
457 | - 将多行的JSX标签写在 `()`里. eslint: [`react/jsx-wrap-multilines`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-wrap-multilines.md)
458 |
459 | ```jsx
460 | // bad
461 | render() {
462 | return
463 |
464 | ;
465 | }
466 |
467 | // good
468 | render() {
469 | return (
470 |
471 |
472 |
473 | );
474 | }
475 |
476 | // good, 单行可以不需要
477 | render() {
478 | const body = hello
;
479 | return {body};
480 | }
481 | ```
482 |
483 | ## Tags 标签
484 |
485 | - 对于没有子元素的标签来说总是自己关闭标签. eslint: [`react/self-closing-comp`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/self-closing-comp.md)
486 |
487 | ```jsx
488 | // bad
489 |
490 |
491 | // good
492 |
493 | ```
494 |
495 | - 如果模块有多行的属性, 关闭标签时新建一行. eslint: [`react/jsx-closing-bracket-location`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-closing-bracket-location.md)
496 |
497 | ```jsx
498 | // bad
499 |
502 |
503 | // good
504 |
508 | ```
509 |
510 | ## Methods 函数
511 |
512 | - 使用箭头函数来获取本地变量.
513 |
514 | ```jsx
515 | function ItemList(props) {
516 | return (
517 |
518 | {props.items.map((item, index) => (
519 | - doSomethingWith(item.name, index)}
522 | />
523 | ))}
524 |
525 | );
526 | }
527 | ```
528 |
529 | - 当在 `render()` 里使用事件处理方法时,提前在构造函数里把 `this` 绑定上去. eslint: [`react/jsx-no-bind`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-bind.md)
530 |
531 | > 为什么? 在每次 `render` 过程中, 再调用 `bind` 都会新建一个新的函数,浪费资源.
532 |
533 | ```jsx
534 | // bad
535 | class extends React.Component {
536 | onClickDiv() {
537 | // do stuff
538 | }
539 |
540 | render() {
541 | return ;
542 | }
543 | }
544 |
545 | // good
546 | class extends React.Component {
547 | constructor(props) {
548 | super(props);
549 |
550 | this.onClickDiv = this.onClickDiv.bind(this);
551 | }
552 |
553 | onClickDiv() {
554 | // do stuff
555 | }
556 |
557 | render() {
558 | return ;
559 | }
560 | }
561 | ```
562 |
563 | - 在React模块中,不要给所谓的私有函数添加 `_` 前缀,本质上它并不是私有的.
564 |
565 | > 为什么?`_` 下划线前缀在某些语言中通常被用来表示私有变量或者函数。但是不像其他的一些语言,在JS中没有原生支持所谓的私有变量,所有的变量函数都是共有的。尽管你的意图是使它私有化,在之前加上下划线并不会使这些变量私有化,并且所有的属性(包括有下划线前缀及没有前缀的)都应该被视为是共有的。了解更多详情请查看Issue [#1024](https://github.com/airbnb/javascript/issues/1024), 和 [#490](https://github.com/airbnb/javascript/issues/490) 。
566 |
567 | ```jsx
568 | // bad
569 | React.createClass({
570 | _onClickSubmit() {
571 | // do stuff
572 | },
573 |
574 | // other stuff
575 | });
576 |
577 | // good
578 | class extends React.Component {
579 | onClickSubmit() {
580 | // do stuff
581 | }
582 |
583 | // other stuff
584 | }
585 | ```
586 |
587 | - 在 `render` 方法中总是确保 `return` 返回值. eslint: [`react/require-render-return`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/require-render-return.md)
588 |
589 | ```jsx
590 | // bad
591 | render() {
592 | ();
593 | }
594 |
595 | // good
596 | render() {
597 | return ();
598 | }
599 | ```
600 |
601 | ## Ordering React 模块生命周期
602 |
603 | - `class extends React.Component` 的生命周期函数:
604 |
605 | 1. 可选的 `static` 方法
606 | 1. `constructor` 构造函数
607 | 1. `getChildContext` 获取子元素内容
608 | 1. `componentWillMount` 模块渲染前
609 | 1. `componentDidMount` 模块渲染后
610 | 1. `componentWillReceiveProps` 模块将接受新的数据
611 | 1. `shouldComponentUpdate` 判断模块需不需要重新渲染
612 | 1. `componentWillUpdate` 上面的方法返回 `true`, 模块将重新渲染
613 | 1. `componentDidUpdate` 模块渲染结束
614 | 1. `componentWillUnmount` 模块将从DOM中清除, 做一些清理任务
615 | 1. *点击回调或者事件处理器* 如 `onClickSubmit()` 或 `onChangeDescription()`
616 | 1. *`render` 里的 getter 方法* 如 `getSelectReason()` 或 `getFooterContent()`
617 | 1. *可选的 render 方法* 如 `renderNavigation()` 或 `renderProfilePicture()`
618 | 1. `render` render() 方法
619 |
620 | - 如何定义 `propTypes`, `defaultProps`, `contextTypes`, 等等其他属性...
621 |
622 | ```jsx
623 | import React from 'react';
624 | import PropTypes from 'prop-types';
625 |
626 | const propTypes = {
627 | id: PropTypes.number.isRequired,
628 | url: PropTypes.string.isRequired,
629 | text: PropTypes.string,
630 | };
631 |
632 | const defaultProps = {
633 | text: 'Hello World',
634 | };
635 |
636 | class Link extends React.Component {
637 | static methodsAreOk() {
638 | return true;
639 | }
640 |
641 | render() {
642 | return {this.props.text};
643 | }
644 | }
645 |
646 | Link.propTypes = propTypes;
647 | Link.defaultProps = defaultProps;
648 |
649 | export default Link;
650 | ```
651 |
652 | - `React.createClass` 的生命周期函数,与使用class稍有不同: eslint: [`react/sort-comp`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/sort-comp.md)
653 |
654 | 1. `displayName` 设定模块名称
655 | 1. `propTypes` 设置属性的类型
656 | 1. `contextTypes` 设置上下文类型
657 | 1. `childContextTypes` 设置子元素上下文类型
658 | 1. `mixins` 添加一些mixins
659 | 1. `statics`
660 | 1. `defaultProps` 设置默认的属性值
661 | 1. `getDefaultProps` 获取默认属性值
662 | 1. `getInitialState` 或者初始状态
663 | 1. `getChildContext`
664 | 1. `componentWillMount`
665 | 1. `componentDidMount`
666 | 1. `componentWillReceiveProps`
667 | 1. `shouldComponentUpdate`
668 | 1. `componentWillUpdate`
669 | 1. `componentDidUpdate`
670 | 1. `componentWillUnmount`
671 | 1. *clickHandlers or eventHandlers* like `onClickSubmit()` or `onChangeDescription()`
672 | 1. *getter methods for `render`* like `getSelectReason()` or `getFooterContent()`
673 | 1. *Optional render methods* like `renderNavigation()` or `renderProfilePicture()`
674 | 1. `render`
675 |
676 | ## isMounted
677 |
678 | - 不要再使用 `isMounted`. eslint: [`react/no-is-mounted`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-is-mounted.md)
679 |
680 | > 为什么? [`isMounted` 反人类设计模式:()][anti-pattern], 在 ES6 classes 中无法使用, 官方将在未来的版本里删除此方法.
681 |
682 | [anti-pattern]: https://facebook.github.io/react/blog/2015/12/16/ismounted-antipattern.html
683 |
684 | **[⬆ 回到顶部](#内容目录)**
685 |
--------------------------------------------------------------------------------