├── README.md ├── linters ├── module-2 │ └── non-react │ │ └── .eslintrc └── module-3 │ ├── .eslintrc │ └── linter-setup.md └── es5 └── README.md /README.md: -------------------------------------------------------------------------------- 1 | # Turing JavaScript Style Guide() { 2 | 3 | *A principally decent approach to JavaScript* 4 | 5 | other style guides 6 | 7 | - [HTML](https://github.com/turingschool-examples/html) 8 | - [CSS](https://github.com/turingschool-examples/css) 9 | 10 | ### Cohort Specific 11 | 12 | #### FEE Module 1 13 | 14 | - [JavaScript](es5/) 15 | 16 | #### FEE Module 2 17 | 18 | - [.eslintrc for non-react projects](linters/module-2/non-react/.eslintrc) 19 | 20 | #### FEE Module 3 21 | 22 | - [Linter Setup for React](linters/module-3/linter-setup.md) 23 | 24 | This style guide has been adapted from [the airbnb javascript style guide](https://github.com/airbnb/javascript) 25 | 26 | # }; 27 | -------------------------------------------------------------------------------- /linters/module-2/non-react/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "commonjs": true, 5 | "es6": true, 6 | "mocha": true 7 | }, 8 | "extends": "eslint:recommended", 9 | "parserOptions": { "sourceType": "module" }, 10 | "rules": { 11 | "eqeqeq": ["error", "always"], 12 | "brace-style": "error", 13 | "comma-spacing": ["warn", { "before": false, "after": true }], 14 | "curly": "error", 15 | "semi-spacing": ["error", { "before": false, "after": true }], 16 | "indent": ["warn", 2], 17 | "key-spacing": ["error", { "beforeColon": false, "afterColon": true }], 18 | "keyword-spacing": ["error", { "before": true, "after": true }], 19 | "linebreak-style": ["error", "unix"], 20 | "max-len": ["warn", 80], 21 | "new-cap": ["error", { "newIsCap": true }], 22 | "object-shorthand": ["error", "always"], 23 | "space-before-blocks": ["error", { "functions": "always", "keywords": "always", "classes": "always" }], 24 | "space-infix-ops": ["error", { "int32Hint": false }] 25 | } 26 | } -------------------------------------------------------------------------------- /linters/module-3/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "extends": [ 4 | "eslint:recommended", 5 | "plugin:react/recommended" 6 | ], 7 | "plugins": [ 8 | "react" 9 | ], 10 | "env": { 11 | "browser": true, 12 | "mocha": true, 13 | "node": true, 14 | "es6": true 15 | }, 16 | // Having a problem with one of these rules? Learn more about it here: https://eslint.org/docs/rules/ 17 | "rules": { 18 | "eqeqeq": ["error", "always"], 19 | "getter-return": ["error", { "allowImplicit": true }], 20 | "indent": ["warn", 2], 21 | "no-template-curly-in-string": "error", 22 | "semi": ["error", "always"], 23 | "array-bracket-spacing": ["error", "never"], 24 | "block-spacing": ["error", "always"], 25 | "brace-style": ["error", "1tbs", { "allowSingleLine": true }], 26 | "camelcase": "warn", 27 | "comma-dangle": ["error", "never"], 28 | "comma-spacing": ["error", { "before": false, "after": true }], 29 | "comma-style": ["error", "last"], 30 | "computed-property-spacing": ["error", "never"], 31 | "func-call-spacing": ["error", "never"], 32 | "keyword-spacing": ["error", { "before": true, "after": true }], 33 | "max-len": ["warn", 80], 34 | "no-duplicate-imports": "error", 35 | "id-length": "error", 36 | "id-blacklist": ["error", "data", "err", "e", "cb", "callback", "payload", "obj", "arr"], 37 | "max-depth": ["warn", 4] 38 | }, 39 | "globals": { 40 | "expect": true 41 | } 42 | } -------------------------------------------------------------------------------- /linters/module-3/linter-setup.md: -------------------------------------------------------------------------------- 1 | # Linter Setup 2 | 3 | During mod 3 we want y'all to use airbnb's eslint config for your projects. 4 | 5 | Here is a list of setup instructions for adding it to your project along with a lint script. 6 | 7 | ## Steps 8 | 9 | ### 1. Add eslint-config-airbnb and babel-eslint as a dev dependency 10 | * `npm i eslint-config-airbnb -D` 11 | * `npm i babel-eslint -D` 12 | 13 | ### 2. Add a `lint` script to your package.json file 14 | 15 | ```json 16 | // update the scripts and eslintConfig portions of your package.json to match below 17 | "scripts": { 18 | "start": "react-scripts start", 19 | "build": "react-scripts build", 20 | "test": "react-scripts test", 21 | "eject": "react-scripts eject", 22 | "lint": "eslint src/**/*.js" 23 | }, 24 | ``` 25 | 26 | And that's it! Now you can lint your application by running: 27 | * `npm run lint` 28 | 29 | ### 3. Add an .eslintrc file to override some of the airbnb rules: 30 | 31 | Create a `.eslintrc` file in your project's root 32 | 33 | ```json 34 | // Use this file as a starting point for your project's .eslintrc. 35 | // By default we're using airbnb's .eslintrc 36 | 37 | { 38 | "extends": ["airbnb", "react-app"], 39 | "parser": "babel-eslint", 40 | "ignorePatterns": ["node_modules/", "src/serviceWorker.js", "src/reportWebVitals.js"], 41 | "rules": { 42 | "react/react-in-jsx-scope": "off", 43 | "import/no-extraneous-dependencies": ["error", { "devDependencies": true }], 44 | "react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }], 45 | "react/forbid-prop-types": 0, 46 | } 47 | } 48 | ``` 49 | -------------------------------------------------------------------------------- /es5/README.md: -------------------------------------------------------------------------------- 1 | # Turing JavaScript Style Guide() { 2 | 3 | *A primarily decent approach to JavaScript* 4 | 5 | ## Table of Contents 6 | 7 | 1. [Whitespace](#whitespace) 8 | 1. [Types](#types) 9 | 1. [Objects](#objects) 10 | 1. [Arrays](#arrays) 11 | 1. [Strings](#strings) 12 | 1. [Functions](#functions) 13 | 1. [Properties](#properties) 14 | 1. [Variables](#variables) 15 | 1. [Comparison Operators & Equality](#comparison-operators--equality) 16 | 1. [Blocks](#blocks) 17 | 1. [Commas](#commas) 18 | 1. [Semicolons](#semicolons) 19 | 1. [Naming Conventions](#naming-conventions) 20 | 21 | ## Whitespace 22 | 23 | - Use soft tabs set to 2 spaces. 24 | 25 | ```javascript 26 | // bad 27 | function() { 28 | ∙∙∙∙var name; 29 | } 30 | 31 | // bad 32 | function() { 33 | ∙var name; 34 | } 35 | 36 | // good 37 | function() { 38 | ∙∙var name; 39 | } 40 | ``` 41 | 42 | - Place 1 space before the leading curly brace. 43 | 44 | ```javascript 45 | // bad 46 | function test(){ 47 | console.log('test'); 48 | } 49 | 50 | // good 51 | function test() { 52 | console.log('test'); 53 | } 54 | ``` 55 | 56 | - Place 1 space before the opening parenthesis in control statements (`if`, `else if`, `while`, etc.). 57 | 58 | ```javascript 59 | // bad 60 | if(isJedi) { 61 | fight(); 62 | } 63 | 64 | // good 65 | if (isJedi) { 66 | fight(); 67 | } 68 | ``` 69 | 70 | - Place no space before the argument list in function calls and declarations. 71 | 72 | ```javascript 73 | // bad 74 | function fight () { 75 | console.log ('Swooosh!'); 76 | } 77 | 78 | // good 79 | function fight() { 80 | console.log('Swooosh!'); 81 | } 82 | ``` 83 | 84 | - Set off operators with spaces. 85 | 86 | ```javascript 87 | // bad 88 | var x=y+5; 89 | 90 | // good 91 | var x = y + 5; 92 | ``` 93 | 94 | - Leave a blank line after blocks and before the next statement 95 | 96 | ```javascript 97 | // bad 98 | if (foo) { 99 | return bar; 100 | } 101 | return baz; 102 | 103 | // good 104 | if (foo) { 105 | return bar; 106 | } 107 | 108 | return baz; 109 | 110 | // bad 111 | var obj = { 112 | foo: function () { 113 | }, 114 | bar: function () { 115 | } 116 | }; 117 | return obj; 118 | 119 | // good 120 | var obj = { 121 | foo: function () { 122 | }, 123 | 124 | bar: function () { 125 | } 126 | }; 127 | 128 | return obj; 129 | ``` 130 | 131 | **[back to top](#table-of-contents)** 132 | 133 | ## Types 134 | 135 | - **Primitives**: When you access a primitive type you work directly on its value. 136 | 137 | + `string` 138 | + `number` 139 | + `boolean` 140 | + `null` 141 | + `undefined` 142 | 143 | ```javascript 144 | var foo = 1; 145 | var bar = foo; 146 | 147 | bar = 9; 148 | 149 | console.log(foo, bar); // => 1, 9 150 | ``` 151 | - **Complex**: When you access a complex type you work on a reference to its value. 152 | 153 | + `object` 154 | + `array` 155 | + `function` 156 | 157 | ```javascript 158 | var foo = [1, 2]; 159 | var bar = foo; 160 | 161 | bar[0] = 9; 162 | 163 | console.log(foo[0], bar[0]); // => 9, 9 164 | ``` 165 | 166 | **[back to top](#table-of-contents)** 167 | 168 | ## Objects 169 | 170 | - Use the literal syntax for generic object creation. 171 | 172 | ```javascript 173 | // bad 174 | var item = new Object(); 175 | 176 | // good 177 | var item = {}; 178 | ``` 179 | 180 | - 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). 181 | 182 | ```javascript 183 | // bad 184 | var superman = { 185 | default: { clark: 'kent' }, 186 | private: true 187 | }; 188 | 189 | // good 190 | var superman = { 191 | defaults: { clark: 'kent' }, 192 | hidden: true 193 | }; 194 | ``` 195 | 196 | - Use readable synonyms in place of reserved words. 197 | 198 | ```javascript 199 | // bad 200 | var superman = { 201 | class: 'alien' 202 | }; 203 | 204 | // bad 205 | var superman = { 206 | klass: 'alien' 207 | }; 208 | 209 | // good 210 | var superman = { 211 | type: 'alien' 212 | }; 213 | ``` 214 | 215 | **[back to top](#table-of-contents)** 216 | 217 | ## Arrays 218 | 219 | - Use the literal syntax for array creation. 220 | 221 | ```javascript 222 | // bad 223 | var items = new Array(); 224 | 225 | // good 226 | var items = []; 227 | ``` 228 | 229 | - Use Array#push instead of direct assignment to add items to an array. 230 | 231 | ```javascript 232 | var someStack = []; 233 | 234 | 235 | // bad 236 | someStack[someStack.length] = 'abracadabra'; 237 | 238 | // good 239 | someStack.push('abracadabra'); 240 | ``` 241 | 242 | **[back to top](#table-of-contents)** 243 | 244 | 245 | ## Strings 246 | 247 | - Use single quotes `''` for strings. 248 | 249 | ```javascript 250 | // bad 251 | var name = "Bob Parr"; 252 | 253 | // good 254 | var name = 'Bob Parr'; 255 | 256 | // bad 257 | var fullName = "Bob " + this.lastName; 258 | 259 | // good 260 | var fullName = 'Bob ' + this.lastName; 261 | ``` 262 | 263 | **[back to top](#table-of-contents)** 264 | 265 | 266 | ## Functions 267 | 268 | - Function expressions: 269 | 270 | ```javascript 271 | // anonymous function expression 272 | var anonymous = function() { 273 | return true; 274 | }; 275 | 276 | // named function expression 277 | var named = function named() { 278 | return true; 279 | }; 280 | ``` 281 | 282 | - Never name a parameter `arguments`. This will take precedence over the `arguments` object that is given to every function scope. 283 | 284 | ```javascript 285 | // bad 286 | function nope(name, options, arguments) { 287 | // ...stuff... 288 | } 289 | 290 | // good 291 | function yup(name, options, args) { 292 | // ...stuff... 293 | } 294 | ``` 295 | 296 | **[back to top](#table-of-contents)** 297 | 298 | 299 | 300 | ## Properties 301 | 302 | - Use dot notation when accessing properties. 303 | 304 | ```javascript 305 | var luke = { 306 | jedi: true, 307 | age: 28 308 | }; 309 | 310 | // bad 311 | var isJedi = luke['jedi']; 312 | 313 | // good 314 | var isJedi = luke.jedi; 315 | ``` 316 | 317 | - Use bracket notation `[]` when accessing properties with a variable. 318 | 319 | ```javascript 320 | var luke = { 321 | jedi: true, 322 | age: 28 323 | }; 324 | 325 | function getProp(prop) { 326 | return luke[prop]; 327 | } 328 | 329 | var isJedi = getProp('jedi'); 330 | ``` 331 | 332 | **[back to top](#table-of-contents)** 333 | 334 | 335 | ## Variables 336 | 337 | - 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. 338 | 339 | ```javascript 340 | // bad 341 | superPower = new SuperPower(); 342 | 343 | // good 344 | var superPower = new SuperPower(); 345 | ``` 346 | 347 | - 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. 348 | 349 | ```javascript 350 | // bad 351 | var i; 352 | var items = getItems(); 353 | var dragonball; 354 | var goSportsTeam = true; 355 | var len; 356 | 357 | // good 358 | var items = getItems(); 359 | var goSportsTeam = true; 360 | var dragonball; 361 | var length; 362 | var i; 363 | ``` 364 | 365 | - Assign variables at the top of their scope. This helps avoid issues with variable declaration and assignment hoisting related issues. 366 | 367 | ```javascript 368 | // bad 369 | function () { 370 | test(); 371 | console.log('doing stuff..'); 372 | 373 | //..other stuff.. 374 | 375 | var name = getName(); 376 | 377 | if (name === 'test') { 378 | return false; 379 | } 380 | 381 | return name; 382 | } 383 | 384 | // good 385 | function () { 386 | var name = getName(); 387 | 388 | test(); 389 | console.log('doing stuff..'); 390 | 391 | //..other stuff.. 392 | 393 | if (name === 'test') { 394 | return false; 395 | } 396 | 397 | return name; 398 | } 399 | 400 | // bad - unnecessary function call 401 | function () { 402 | var name = getName(); 403 | 404 | if (!arguments.length) { 405 | return false; 406 | } 407 | 408 | this.setFirstName(name); 409 | 410 | return true; 411 | } 412 | 413 | // good 414 | function () { 415 | var name; 416 | 417 | if (!arguments.length) { 418 | return false; 419 | } 420 | 421 | name = getName(); 422 | this.setFirstName(name); 423 | 424 | return true; 425 | } 426 | ``` 427 | 428 | **[back to top](#table-of-contents)** 429 | 430 | ## Comparison Operators & Equality 431 | 432 | - Use `===` and `!==` over `==` and `!=`. 433 | - Conditional statements such as the `if` statement evaluate their expression using coercion with the `ToBoolean` abstract method and always follow these simple rules: 434 | 435 | + **Objects** evaluate to **true** 436 | + **Undefined** evaluates to **false** 437 | + **Null** evaluates to **false** 438 | + **Booleans** evaluate to **the value of the boolean** 439 | + **Numbers** evaluate to **false** if **+0, -0, or NaN**, otherwise **true** 440 | + **Strings** evaluate to **false** if an empty string `''`, otherwise **true** 441 | 442 | ```javascript 443 | if ([0]) { 444 | // true 445 | // An array is an object, objects evaluate to true 446 | } 447 | ``` 448 | 449 | - Use shortcuts. 450 | 451 | ```javascript 452 | // bad 453 | if (name !== '') { 454 | // ...stuff... 455 | } 456 | 457 | // good 458 | if (name) { 459 | // ...stuff... 460 | } 461 | 462 | // bad 463 | if (collection.length > 0) { 464 | // ...stuff... 465 | } 466 | 467 | // good 468 | if (collection.length) { 469 | // ...stuff... 470 | } 471 | ``` 472 | 473 | - For more information see [Truth Equality and JavaScript](http://javascriptweblog.wordpress.com/2011/02/07/truth-equality-and-javascript/#more-2108) by Angus Croll. 474 | 475 | **[back to top](#table-of-contents)** 476 | 477 | 478 | ## Blocks 479 | 480 | - Use braces with all multi-line blocks. 481 | 482 | ```javascript 483 | // bad 484 | if (test) 485 | return false; 486 | 487 | // good 488 | if (test) return false; 489 | 490 | // good 491 | if (test) { 492 | return false; 493 | } 494 | 495 | // bad 496 | function () { return false; } 497 | 498 | // good 499 | function () { 500 | return false; 501 | } 502 | ``` 503 | 504 | - If you're using multi-line blocks with `if` and `else`, put `else` on the same line as your 505 | `if` block's closing brace. 506 | 507 | ```javascript 508 | // bad 509 | if (test) { 510 | thing1(); 511 | thing2(); 512 | } 513 | else { 514 | thing3(); 515 | } 516 | 517 | // good 518 | if (test) { 519 | thing1(); 520 | thing2(); 521 | } else { 522 | thing3(); 523 | } 524 | ``` 525 | 526 | 527 | **[back to top](#table-of-contents)** 528 | 529 | ## Commas 530 | 531 | - Leading commas: **Nope.** 532 | 533 | ```javascript 534 | // bad 535 | var story = [ 536 | once 537 | , upon 538 | , aTime 539 | ]; 540 | 541 | // good 542 | var story = [ 543 | once, 544 | upon, 545 | aTime 546 | ]; 547 | 548 | // bad 549 | var hero = { 550 | firstName: 'Bob' 551 | , lastName: 'Parr' 552 | , heroName: 'Mr. Incredible' 553 | , superPower: 'strength' 554 | }; 555 | 556 | // good 557 | var hero = { 558 | firstName: 'Bob', 559 | lastName: 'Parr', 560 | heroName: 'Mr. Incredible', 561 | superPower: 'strength' 562 | }; 563 | ``` 564 | 565 | - 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)): 566 | 567 | > 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. 568 | 569 | ```javascript 570 | // bad 571 | var hero = { 572 | firstName: 'Kevin', 573 | lastName: 'Flynn', 574 | }; 575 | 576 | var heroes = [ 577 | 'Batman', 578 | 'Superman', 579 | ]; 580 | 581 | // good 582 | var hero = { 583 | firstName: 'Kevin', 584 | lastName: 'Flynn' 585 | }; 586 | 587 | var heroes = [ 588 | 'Batman', 589 | 'Superman' 590 | ]; 591 | ``` 592 | 593 | **[back to top](#table-of-contents)** 594 | 595 | 596 | ## Semicolons 597 | 598 | - **Yup.** 599 | 600 | ```javascript 601 | // bad 602 | (function () { 603 | var name = 'Skywalker' 604 | return name 605 | })() 606 | 607 | // good 608 | (function () { 609 | var name = 'Skywalker'; 610 | return name; 611 | })(); 612 | 613 | // good (guards against the function becoming an argument when two files with IIFEs are concatenated) 614 | ;(function () { 615 | var name = 'Skywalker'; 616 | return name; 617 | })(); 618 | ``` 619 | 620 | [Read more](http://stackoverflow.com/a/7365214/1712802). 621 | 622 | **[back to top](#table-of-contents)** 623 | 624 | 625 | ## Naming Conventions 626 | 627 | - Avoid single letter names. Be descriptive with your naming. 628 | 629 | ```javascript 630 | // bad 631 | function q() { 632 | // ...stuff... 633 | } 634 | 635 | // good 636 | function query() { 637 | // ..stuff.. 638 | } 639 | ``` 640 | 641 | - Use camelCase when naming objects, functions, and instances. 642 | 643 | ```javascript 644 | // bad 645 | var OBJEcttsssss = {}; 646 | var this_is_my_object = {}; 647 | var o = {}; 648 | function c() {} 649 | 650 | // good 651 | var thisIsMyObject = {}; 652 | function thisIsMyFunction() {} 653 | ``` 654 | 655 | - Use PascalCase when naming classes. 656 | 657 | ```javascript 658 | // bad 659 | class user { 660 | constructor(options) { 661 | this.name = options.name; 662 | } 663 | } 664 | 665 | var bad = new user({ 666 | name: 'nope' 667 | }); 668 | 669 | // good 670 | class User { 671 | constructor(options) { 672 | this.name = options.name; 673 | } 674 | } 675 | 676 | var good = new User({ 677 | name: 'yup' 678 | }); 679 | ``` 680 | 681 | - Name your functions. This is helpful for stack traces. 682 | 683 | ```javascript 684 | // bad 685 | var log = function (msg) { 686 | console.log(msg); 687 | }; 688 | 689 | // good 690 | var log = function log(msg) { 691 | console.log(msg); 692 | }; 693 | ``` 694 | 695 | - **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. 696 | 697 | **[back to top](#table-of-contents)** 698 | 699 | # }; 700 | --------------------------------------------------------------------------------