├── .eslintrc ├── README.md ├── es6.md └── postgres.md /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "ecmaFeatures": { 3 | "arrowFunctions": true, 4 | "binaryLiterals": false, 5 | "blockBindings": true, 6 | "classes": true, 7 | "defaultParams": true, 8 | "destructuring": true, 9 | "forOf": true, 10 | "generators": true, 11 | "modules": false, 12 | "objectLiteralComputedProperties": true, 13 | "objectLiteralDuplicateProperties": false, 14 | "objectLiteralShorthandMethods": true, 15 | "objectLiteralShorthandProperties": true, 16 | "octalLiterals": false, 17 | "regexUFlag": false, 18 | "regexYFlag": false, 19 | "restParams": true, 20 | "spread": true, 21 | "superInFunctions": true, 22 | "templateStrings": true, 23 | "unicodePointEscapes": true, 24 | "globalReturn": false, 25 | "jsx": true 26 | }, 27 | "env": { 28 | "browser": true, 29 | "node": true 30 | }, 31 | "parser": "babel-eslint", 32 | "plugins": [ 33 | "react" 34 | ], 35 | "rules": { 36 | /* Possible Errors */ 37 | "comma-dangle": [1, "always-multiline"], //disallow or enforce trailing commas (recommended) 38 | "no-cond-assign": [1, "except-parens"], //disallow assignment in conditional expressions (recommended) 39 | "no-console": 0, //disallow use of console in the node environment (recommended) 40 | "no-constant-condition": 1, //disallow use of constant expressions in conditions (recommended) 41 | "no-control-regex": 1, //disallow control characters in regular expressions (recommended) 42 | "no-debugger": 1, //disallow use of debugger (recommended) 43 | "no-dupe-args": 1, //disallow duplicate arguments in functions (recommended) 44 | "no-dupe-keys": 1, //disallow duplicate keys when creating object literals (recommended) 45 | "no-duplicate-case": 1, //disallow a duplicate case label. (recommended) 46 | "no-empty-character-class": 1, //disallow the use of empty character classes in regular expressions (recommended) 47 | "no-empty": 1, //disallow empty statements (recommended) 48 | "no-ex-assign": 1, //disallow assigning to the exception in a catch block (recommended) 49 | "no-extra-boolean-cast": 1, //disallow double-negation boolean casts in a boolean context (recommended) 50 | "no-extra-parens": 0, //disallow unnecessary parentheses 51 | "no-extra-semi": 1, //disallow unnecessary semicolons (recommended) (fixable) 52 | "no-func-assign": 1, //disallow overwriting functions written as function declarations (recommended) 53 | "no-inner-declarations": [1, "functions"], //disallow function or variable declarations in nested blocks (recommended) 54 | "no-invalid-regexp": 1, //disallow invalid regular expression strings in the RegExp constructor (recommended) 55 | "no-irregular-whitespace": 1, //disallow irregular whitespace outside of strings and comments (recommended) 56 | "no-negated-in-lhs": 1, //disallow negation of the left operand of an in expression (recommended) 57 | "no-obj-calls": 1, //disallow the use of object properties of the global object (Math and JSON) as functions (recommended) 58 | "no-regex-spaces": 1, //disallow multiple spaces in a regular expression literal (recommended) 59 | "no-sparse-arrays": 1, //disallow sparse arrays (recommended) 60 | "no-unexpected-multiline": 1, //Avoid code that looks like two expressions but is actually one 61 | "no-unreachable": 1, //disallow unreachable statements after a return, throw, continue, or break statement (recommended) 62 | "use-isnan": 1, //disallow comparisons with the value NaN (recommended) 63 | "valid-jsdoc": 1, //Ensure JSDoc comments are valid 64 | "valid-typeof": 1, //Ensure that the results of typeof are compared against a valid string (recommended) 65 | 66 | /* Best Practices */ 67 | "accessor-pairs": 0, //Enforces getter/setter pairs in objects 68 | "block-scoped-var": 1, // treat var statements as if they were block scoped 69 | "complexity": 0, //specify the maximum cyclomatic complexity allowed in a program 70 | "consistent-return": 1, //require return statements to either always or never specify values 71 | "curly": [1, "all"], //specify curly brace conventions for all control statements 72 | "default-case": 1, //require default case in switch statements 73 | "dot-location": [1, "property"], //enforces consistent newlines before or after dots 74 | "dot-notation": [1, { "allowKeywords": true, "allowPattern": "" }], //encourages use of dot notation whenever possible 75 | "eqeqeq": 1, //require the use of === and !== (fixable) 76 | "guard-for-in": 0, //make sure for-in loops have an if statement 77 | "no-alert": 1, //disallow the use of alert, confirm, and prompt 78 | "no-caller": 1, //disallow use of arguments.caller or arguments.callee 79 | "no-case-declarations": 0, // disallow lexical declarations in case clauses 80 | "no-div-regex": 1, //disallow division operators explicitly at beginning of regular expression 81 | "no-else-return": 1, //disallow else after a return in an if 82 | "no-empty-label": 1, //disallow use of labels for anything other than loops and switches 83 | "no-empty-pattern": 1, //disallow use of empty destructuring patterns 84 | "no-eq-null": 1, //disallow comparisons to null without a type-checking operator 85 | "no-eval": 1, //disallow use of eval() 86 | "no-extend-native": 1, //disallow adding to native types 87 | "no-extra-bind": 1, //disallow unnecessary function binding 88 | "no-fallthrough": 1, //disallow fallthrough of case statements (recommended) 89 | "no-floating-decimal": 1, //disallow the use of leading or trailing decimal points in numeric literals 90 | "no-implicit-coercion": 1, //disallow the type conversions with shorter notations 91 | "no-implied-eval": 1, //disallow use of eval()-like methods 92 | "no-invalid-this": 0, //disallow this keywords outside of classes or class-like objects 93 | "no-iterator": 1, //disallow usage of __iterator__ property 94 | "no-labels": 1, //disallow use of labeled statements 95 | "no-lone-blocks": 1, //disallow unnecessary nested blocks 96 | "no-loop-func": 1, //disallow creation of functions within loops 97 | "no-magic-numbers": [1, { "ignore": [-1, 0, 1] }], // disallow the use of magic numbers 98 | "no-multi-spaces": 1, //disallow use of multiple spaces (fixable) 99 | "no-multi-str": 1, //disallow use of multiline strings 100 | "no-native-reassign": 1, //disallow reassignments of native objects 101 | "no-new-func": 1, //disallow use of new operator for Function object 102 | "no-new-wrappers": 1, //disallows creating new instances of String,Number, and Boolean 103 | "no-new": 1, //disallow use of the new operator when not part of an assignment or comparison 104 | "no-octal-escape": 1, //disallow use of octal escape sequences in string literals, such as var foo = "Copyright \251"; 105 | "no-octal": 1, //disallow use of octal literals (recommended) 106 | "no-param-reassign": [1, {"props": false}], //disallow reassignment of function parameters 107 | "no-process-env": 0, //disallow use of process.env 108 | "no-proto": 1, //disallow usage of __proto__ property 109 | "no-redeclare": 1, //disallow declaring the same variable more than once (recommended) 110 | "no-return-assign": 1, //disallow use of assignment in return statement 111 | "no-script-url": 1, //disallow use of javascript: urls. 112 | "no-self-compare": 1, //disallow comparisons where both sides are exactly the same 113 | "no-sequences": 1, //disallow use of the comma operator 114 | "no-throw-literal": 1, //restrict what can be thrown as an exception 115 | "no-unused-expressions": [1, { allowShortCircuit: true, allowTernary: true }], //disallow usage of expressions in statement position 116 | "no-useless-call": 1, //disallow unnecessary .call() and .apply() 117 | "no-useless-concat": 1, //disallow unnecessary concatenation of literals or template literals 118 | "no-void": 0, //disallow use of the void operator 119 | "no-warning-comments": [1, { "terms": ["todo", "fixme"], "location": "start" }], //disallow usage of configurable warning terms in comments e.g. TODO or FIXME 120 | "no-with": 1, //disallow use of the with statement 121 | "radix": 0, // require use of the second argument for parseInt() 122 | "vars-on-top": 1, //require declaration of all vars at the top of their containing scope 123 | "wrap-iife": [1, "inside"], //require immediate function invocation to be wrapped in parentheses 124 | "yoda": [1, "never"], //require or disallow Yoda conditions 125 | 126 | /* Strict Mode */ 127 | "strict": [1, "never"], //controls location of Use Strict Directives 128 | 129 | /* Variables */ 130 | "init-declarations": 0, //enforce or disallow variable initializations at definition 131 | "no-catch-shadow": 1, //disallow the catch clause parameter name being the same as a variable in the outer scope 132 | "no-delete-var": 1, //disallow deletion of variables (recommended) 133 | "no-label-var": 1, //disallow labels that share a name with a variable 134 | "no-shadow-restricted-names": 1, //disallow shadowing of names such as arguments 135 | "no-shadow": 1, //disallow declaration of variables already declared in the outer scope 136 | "no-undef-init": 1, //disallow use of undefined when initializing variables 137 | "no-undef": 1, //disallow use of undeclared variables unless mentioned in a /*global */ block (recommended) 138 | "no-undefined": 1, //disallow use of undefined variable 139 | "no-unused-vars": [1, { "vars": "local", "args": "after-used" }], //disallow declaration of variables that are not used in the code (recommended) 140 | "no-use-before-define": 1, //disallow use of variables before they are defined 141 | 142 | /* Node.js */ 143 | "callback-return": 1, //enforce return after a callback 144 | "global-require": 1, //enforce require() on top-level module scope 145 | "handle-callback-err": 1, //enforce error handling in callbacks 146 | "no-mixed-requires": 1, //disallow mixing regular variable and require declarations 147 | "no-new-require": 1, //disallow use of new operator with the require function 148 | "no-path-concat": 1, //disallow string concatenation with __dirname and __filename 149 | "no-process-exit": 1, //disallow process.exit() 150 | "no-restricted-modules": [1, ""], //restrict usage of specified node modules 151 | "no-sync": 1, //disallow use of synchronous methods 152 | 153 | /* Stylistic Issues */ 154 | "array-bracket-spacing": [1, "never"], //enforce spacing inside array brackets (fixable) 155 | "block-spacing": [1, "always"], //disallow or enforce spaces inside of single line blocks (fixable) 156 | "brace-style": [1, "stroustrup", { "allowSingleLine": true }], //enforce one true brace style 157 | "camelcase": [1, { "properties": "always" }], //require camel case names 158 | "comma-spacing": [1, { "before": false, "after": true }], //enforce spacing before and after comma 159 | "comma-style": [1, "last"], //enforce one true comma style 160 | "computed-property-spacing": 0, //require or disallow padding inside computed properties (fixable) 161 | "consistent-this": 0, //enforce consistent naming when capturing the current execution context 162 | "eol-last": 1, //enforce newline at the end of file, with no multiple empty lines (fixable) 163 | "func-names": 1, //require function expressions to have a name 164 | "func-style": 0, //enforce use of function declarations or expressions 165 | "id-length": 0, //this option enforces minimum and maximum identifier lengths (variable names, property names etc.) 166 | "id-match": [0, "^[a-z]+([A-Z][a-z]*)*$", {"properties": true}], //require identifiers to match the provided regular expression 167 | "indent": [1, 2], //specify tab or space width for your code (fixable) 168 | "jsx-quotes": [1, "prefer-single"], //specify whether double or single quotes should be used in JSX attributes 169 | "key-spacing": [1, { "beforeColon": false, "afterColon": true }], //enforce spacing between keys and values in object literal properties 170 | "linebreak-style": 0, //disallow mixed 'LF' and 'CRLF' as linebreaks 171 | "lines-around-comment": [1, { "beforeLineComment": true, "allowBlockStart": true, "allowObjectStart": true, "allowArrayStart": true }], //enforce empty lines around comments 172 | "max-nested-callbacks": [0, 3], //specify the maximum depth callbacks can be nested 173 | "new-cap": [1, { "capIsNewExceptions": ["NaN", "T.Promise"] }], // require a capital letter for constructors 174 | "new-parens": 1, //disallow the omission of parentheses when invoking a constructor with no arguments 175 | "newline-after-var": 0, //require or disallow an empty newline after variable declarations 176 | "no-array-constructor": 1, //disallow use of the Array constructor 177 | "no-continue": 1, //disallow use of the continue statement 178 | "no-inline-comments": 1, // disallow comments inline after code 179 | "no-lonely-if": 1, //disallow if as the only statement in an else block 180 | "no-mixed-spaces-and-tabs": 1, //disallow mixed spaces and tabs for indentation (recommended) 181 | "no-multiple-empty-lines": [1, { "max": 1 }], //disallow multiple empty lines 182 | "no-negated-condition": 1, //disallow negated conditions 183 | "no-nested-ternary": 0, //disallow nested ternary expressions 184 | "no-new-object": 1, //disallow the use of the Object constructor 185 | "no-restricted-syntax": [1, 186 | "BreakStatement", 187 | "ContinueStatement", 188 | "DoWhileStatement", 189 | "DebuggerStatement", 190 | "LabeledStatement", 191 | "WhileStatement", 192 | "WithStatement", 193 | "ExportAllDeclaration", 194 | "ExportSpecifier", 195 | "ImportNamespaceSpecifier" 196 | ], //disallow use of certain syntax in code 197 | "no-spaced-func": 1, //disallow space between function identifier and application (fixable) 198 | "no-ternary": 0, //disallow the use of ternary operators 199 | "no-trailing-spaces": 1, //disallow trailing whitespace at the end of lines (fixable) 200 | "no-underscore-dangle": 0, //disallow dangling underscores in identifiers 201 | "no-unneeded-ternary": 1, //disallow the use of ternary operators when a simpler alternative exists 202 | "object-curly-spacing": [1, "always"], // require or disallow padding inside curly braces (fixable) 203 | "one-var": [1, "never"], //require or disallow one variable declaration per function 204 | "operator-assignment": [1, "never"], //require assignment operator shorthand where possible or prohibit it entirely 205 | "operator-linebreak": [1, "after"], //enforce operators to be placed before or after line breaks 206 | "padded-blocks": [0, "never"], //enforce padding within blocks 207 | "quote-props": [0, "as-needed"], //require quotes around object literal property names 208 | "quotes": [1, "single"], //specify whether backticks, double or single quotes should be used (fixable) 209 | "require-jsdoc": 0, //Require JSDoc comment 210 | "semi-spacing": [1, { "before": false, "after": true }], //enforce spacing before and after semicolons 211 | "semi": [1, "always"], //require or disallow use of semicolons instead of ASI (fixable) 212 | "sort-vars": 0, //sort variables within the same declaration block 213 | "space-after-keywords": 0, //require a space after certain keywords (fixable) 214 | "space-before-blocks": [1, "always"], //require or disallow a space before blocks (fixable) 215 | "space-before-function-paren": [1, "never"], //require or disallow a space before function opening parenthesis (fixable) 216 | "space-before-keywords": [0, "never"], //require a space before certain keywords (fixable) 217 | "space-in-parens": [1, "never"], //require or disallow spaces inside parentheses 218 | "space-infix-ops": 1, //require spaces around operators (fixable) 219 | "space-return-throw-case": 1, //require a space after return, throw, and case (fixable) 220 | "space-unary-ops": 0, //require or disallow spaces before/after unary operators (fixable) 221 | "spaced-comment": [1, "always"], //require or disallow a space immediately following the // or /* in a comment 222 | "wrap-regex": 1, //require regex literals to be wrapped in parentheses 223 | 224 | /* ECMAScript 6 */ 225 | "arrow-body-style": [1, "as-needed"], // require braces in arrow function body 226 | "arrow-parens": [1, "always"], // require parens in arrow function arguments 227 | "arrow-spacing": [1, { "before": true, "after": true }], //require space before/after arrow function's arrow (fixable) 228 | "constructor-super": 1, //verify calls of super() in constructors 229 | "no-arrow-condition": 1, // disallow arrow functions where a condition is expected 230 | "generator-star-spacing": [1, "after"], // enforce spacing around the * in generator functions (fixable) 231 | "no-class-assign": 1, //disallow modifying variables of class declarations 232 | "no-const-assign": 1, //disallow modifying variables that are declared using const 233 | "no-dupe-class-members": 1, //disallow duplicate name in class members 234 | "no-this-before-super": 1, //disallow use of this/super before calling super() in constructors. 235 | "no-var": 1, //require let or const instead of var 236 | "object-shorthand": 1, // (see Babel section) require method and property shorthand syntax for object literals 237 | "prefer-arrow-callback": 1, //suggest using arrow functions as callbacks 238 | "prefer-const": 1, //suggest using const declaration for variables that are never modified after declared 239 | "prefer-reflect": 1, //suggest using Reflect methods where applicable 240 | "prefer-spread": 1, //suggest using the spread operator instead of .apply(). 241 | "prefer-template": 1, //suggest using template literals instead of strings concatenation 242 | "require-yield": 1, //disallow generator functions that do not have yield 243 | 244 | /* Legacy */ 245 | "max-depth": [0, 3], //specify the maximum depth that blocks can be nested 246 | "max-len": [1, 121, 2], //specify the maximum length of a line in your program 247 | "max-params": 0, //limits the number of parameters that can be used in the function declaration. 248 | "max-statements": 0, //specify the maximum number of statement allowed in a function 249 | "no-bitwise": 1, //disallow use of bitwise operators 250 | "no-plusplus": 1, //disallow use of unary operators, ++ and -- 251 | 252 | /* React */ 253 | "react/display-name": 0, //Prevent missing displayName in a React component definition 254 | "react/forbid-prop-types": 0, //Forbid certain propTypes 255 | "react/jsx-boolean-value": 1, //Enforce boolean attributes notation in JSX 256 | "react/jsx-closing-bracket-location": 0, //Validate closing bracket location in JSX 257 | "react/jsx-curly-spacing": 0, //Enforce or disallow spaces inside of curly braces in JSX attributes 258 | "react/jsx-indent-props": [1, 2], //Validate props indentation in JSX 259 | "react/jsx-key": 1, // Validate JSX has key prop when in array or iterator 260 | "react/jsx-max-props-per-line": 0, //Limit maximum of props on a single line in JSX 261 | "react/jsx-no-bind": 0, // prevent usage of .bind() and arrow functions in JSX props 262 | "react/jsx-no-duplicate-props": 1, //Prevent duplicate properties in JSX 263 | "react/jsx-no-literals": 1, //Prevent usage of unwrapped JSX strings 264 | "react/jsx-no-undef": 1, //Disallow undeclared variables in JSX 265 | "react/jsx-pascal-case": 1, // Enforce PascalCase for user-defined JSX components 266 | "react/jsx-sort-prop-types": 1, //Enforce propTypes declarations alphabetical sorting 267 | "react/jsx-sort-props": 1, //Enforce props alphabetical sorting 268 | "react/jsx-uses-react": 1, //Prevent React to be incorrectly marked as unused 269 | "react/jsx-uses-vars": 1, //Prevent variables used in JSX to be incorrectly marked as unused 270 | "react/no-danger": 1, //Prevent usage of dangerous JSX properties 271 | "react/no-did-mount-set-state": 1, //Prevent usage of setState in componentDidUpdate 272 | "react/no-did-update-set-state": 1, //Prevent usage of setState in componentDidUpdate 273 | "react/no-direct-mutation-state": 1, //Prevent direct mutation of this.state 274 | "react/no-multi-comp": 0, // prevent multiple component definition per file 275 | "react/no-set-state": 0, //Prevent usage of setState 276 | "react/no-unknown-property": 1, //Prevent usage of unknown DOM property 277 | "react/prefer-es6-class": 1, //Use ES6 Class instead of Reacy.createClass 278 | "react/prop-types": 1, //Prevent missing props validation in a React component definition 279 | "react/react-in-jsx-scope": 1, //Prevent missing React when using JSX 280 | "react/require-extension": 1, //Restrict file extensions that may be required 281 | "react/self-closing-comp": 1, //Prevent extra closing tags for components without children 282 | "react/sort-comp": 1, //Enforce component methods order 283 | "react/wrap-multilines": 0 //Prevent missing parentheses around multiline JSX 284 | } 285 | } 286 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This repository contains my coding style guidelines. 2 | 3 | - [ES6 coding guidelines](es6.md) 4 | - [PostgreSQL coding guidelines](postgres.md) 5 | 6 | An [`.eslintrc`](.eslintrc) file with pre-configured rules is available if you wish to use [ESLint](http://eslint.org/). 7 | It currently works under `1.10.1` version. 8 | -------------------------------------------------------------------------------- /es6.md: -------------------------------------------------------------------------------- 1 | # ES6 Coding Style 2 | 3 | This document is intended to provide consistent and helpful coding convention for ES6 code. It should be usable either in Node/IO.js or in the browser. 4 | 5 | The recommended transpiling tool for ES6 to ES5 is [babel](http://babeljs.io/). The recommended bundler for the browser is [webpack](https://github.com/webpack/webpack), but [browserify](http://browserify.org/) is also acceptable. 6 | 7 | The recommended text editor is Sublime Text using [babel-sublime](https://github.com/babel/babel-sublime). Other editors are acceptable, as long as they have proper ES6 and optionally, JSX support. 8 | 9 | Instructions denoted as **must**/**must not** are *mandatory*. Instructions denoted as **should**/**should not** are *preferred*. 10 | 11 | Rationale for each instruction is *italic*. Some instructions are under the *pure convention* rationale: it means that when several, practically equivalent (besides bikeshedding) options are available, we pick one and stick to it to enforce consistency in the codebase. 12 | 13 | ## Evil constructs 14 | 15 | - The following constructs **must not** be used, for both performance and critical security reasons. 16 | 17 | - `eval` and similar `new Function`, `setTimeout(string)`, `setInterval(string)`, `setImmediate(string)` (however `setTimeout(function)` etc. is perfectly fine). 18 | 19 | - `with`, 20 | 21 | - `alert` and `confirm`, 22 | 23 | - primitive type wrapper constructors (`new Number`, `new String`, `new Boolean`, `new Array`, `new Object`), 24 | 25 | - tabs (they are evil, don't use them). 26 | 27 | *`eval` and similar prevents runtime optimizations and leaks the execution context. See [How evil is eval?](https://javascriptweblog.wordpress.com/2010/04/19/how-evil-is-eval/).* 28 | 29 | *`with` present the same kind of issues than `eval`. In addition, it is often ambiguous. See [the MDN with docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/with).* 30 | 31 | *`alert` and `confirm` are legacy of the past. They are synchronously blocking and highly user disruptive.* 32 | 33 | *Primitive type wrappers are slower than their primitive counterparts. They also cause subtle bugs with `instanceof`.* 34 | 35 | ## Strict mode 36 | 37 | - Strict mode **must** be used. However, it **should** be inserted at build time, not in the original source. 38 | 39 | ## Casing 40 | 41 | - Regular identifiers **must** be formatted `likeThis`. 42 | 43 | - Only functions with constructor semantics, classes, or namespaces **must** start with an Uppercase letter (PascalCase), `LikeThis`. 44 | 45 | - Macros (to be processed at build time) **must** be formatted `__LIKE_THIS__`. 46 | 47 | - Magic values (eg. numerical constants) **must** be formatted `LIKE_THIS`. 48 | 49 | - Private properties and methods **must** be formatted `_likeThis`. 50 | 51 | ```js 52 | const regularIdentifier; 53 | function Constructor() { ... } 54 | class Class { ... } 55 | const Namespace = {}; 56 | 57 | if(__MACRO__) { ... } 58 | const SOME_MAGIC_NUMBER = 1337; 59 | const { 60 | _privateMethod() { 61 | ... 62 | } 63 | 64 | publicMethod() { 65 | ... 66 | } 67 | } 68 | ``` 69 | 70 | *Mostly pure convention. Magic values should always be assigned to named constants, not used directly in formulas, for easier debugging and maintenance. Enforcing __lexical__ 'privacy' of methods and properties is possible using closures, but it comes with a performance cost and more coding efforts, when in the vast majority of cases you just want to enforce a __conventional__ privacy: users can violate privacy, at their own risk.* 71 | 72 | 73 | ## Objects 74 | 75 | - Regular objects **must** be created using the Object syntax literal. 76 | 77 | ```js 78 | // bad 79 | const obj = new Object(); 80 | const obj = Object.create(Object.prototype); 81 | 82 | // good 83 | const obj = {}; 84 | ``` 85 | 86 | - Object literals keys **must** be camelCase (this doesn't apply to programmatically generated keys). 87 | 88 | ```js 89 | // bad 90 | const obj = { 91 | 'not-camel-cased': ... 92 | }; 93 | 94 | // good 95 | const obj = { 96 | camelCased: ... 97 | }; 98 | // acceptable 99 | const myKey = 'something-from-somewhere'; 100 | const obj = { 101 | [myKey]: ... 102 | }; 103 | ``` 104 | 105 | - An object declaration **must** have spaces after each `{` and before each `}`. 106 | 107 | - If the declaration is multiline, each line **must** end with a comma, including the last one. 108 | 109 | - If the declaration is not multiline, the last value **must not** end with a comma. 110 | 111 | - In an object declaration, there **must not** be space before each colon but at least one after each colon. 112 | 113 | ```js 114 | // bad 115 | const a = { 116 | k1: v1, 117 | k2: v2 118 | }; 119 | const b = { k1: v1, k2: v2, }; 120 | const c = {k1:v1}; 121 | 122 | // good 123 | const a = { 124 | k1: v1, 125 | k2: v2, 126 | }; 127 | const b = { k1: v1, k2: v2 }; 128 | const c = { k1: v2 }; 129 | ``` 130 | 131 | *Mostly pure convention. The trailing for multiline literals comma helps with adding/removing properties, and yield smaller and easier to read git diffs.* 132 | 133 | ## Arrays 134 | 135 | - Arrays **must** be created using the Array syntax literal. 136 | 137 | ```js 138 | // bad 139 | const a = new Array(); 140 | 141 | // good 142 | const a = []; 143 | ``` 144 | 145 | ## Strings 146 | 147 | - Static strings **must** be declared using single quotes or backticks. 148 | 149 | - Dynamic strings **must** be declared using ES6 template literals (backticks). Dynamic strings **must not** be declared using single- or double-quotes. 150 | 151 | - Never use double-quotes. 152 | 153 | ```js 154 | // bad 155 | const a = "foobar"; 156 | const b = 'foo' + a + 'bar'; 157 | 158 | // acceptable 159 | const c = `foobar`; 160 | 161 | // good 162 | const a = 'foobar'; 163 | const b = `foo${a}bar`; 164 | const c = 'foobar'; 165 | ``` 166 | 167 | *Mostly pure convention. Backticks are always preferred for dynamic strings as they are easier to read and easier to scan.* 168 | 169 | ## var, let, const 170 | 171 | - `var` **must not** be used. 172 | 173 | - `const` **should** be used by default. If you really need to use `let`, its acceptable, but its most often a sign that you should refactor. 174 | 175 | - `const` (or `let`) **must** be used exactly once per variable declaration. 176 | 177 | ```js 178 | // bad 179 | const a = 1, b = 2, c = 3; 180 | 181 | // good 182 | const a = 1; 183 | const b = 2; 184 | const c = 3; 185 | 186 | // actually best 187 | const [a, b, c] = [1, 2, 3]; 188 | ``` 189 | 190 | *`var` is to be considered legacy; there are no practical use cases for `var` anymore. All values (rather than variables) should be `const` (single-assignment) by default; which means that unless otherwise specified, a value can not change behind your back. Mutability is therefore opt-in rather than opt-out. Note however that a `const` object can still be mutated; if you need deep immutability, consider using [`immutable-js`](http://facebook.github.io/immutable-js/).* 191 | 192 | ## Functions 193 | 194 | - Regular (named and hoisted) function declarations **should** be used instead of anonymous functions by default. 195 | 196 | - `new` **must not** be used with functions which are not ES6 classes. 197 | 198 | ```js 199 | // bad 200 | function A() { 201 | 202 | } 203 | const a = new A(); 204 | 205 | // good 206 | class A { 207 | 208 | } 209 | const a = new A(); 210 | ``` 211 | 212 | - When using anonymous functions, arrow function **should** be used instead of anonymous `function`. 213 | 214 | - When using 'anonymous' `function`, a name **must** be given. 215 | 216 | ```js 217 | const a = [1, 2, 3]; 218 | // bad 219 | a.reduce(function(x, y) { return x + y; }, 0); 220 | 221 | // better, but still bad 222 | a.reduce(function sum(x, y) { return x + y; }, 0); 223 | 224 | // acceptable but convoluted 225 | function sum(x, y) { 226 | return x + y; 227 | } 228 | a.reduce(sum, 0); 229 | 230 | 231 | // good 232 | a.reduce((x, y) => x + y, 0); 233 | ``` 234 | 235 | - Parens **must** be used for arrow functions parameters, even when there is only one parameter. 236 | 237 | ```js 238 | // bad 239 | const triple = x => 3 * x; 240 | 241 | // good 242 | const triple = (x) => 3 * x; 243 | ``` 244 | 245 | - Arrow functions **should** be used instead of `Function.prototype.bind` when applicable. `self` / `_this` / `that` trickery **must not** be used. 246 | 247 | ```js 248 | function method(...params) { 249 | ... 250 | } 251 | 252 | // terribly bad 253 | const self = this; 254 | const boundMethod = function(...params) { 255 | return method.apply(self, params); 256 | } 257 | 258 | // acceptable 259 | const boundMethod = method.bind(this); 260 | 261 | // best 262 | const boundMethod = (...params) => method.apply(this, params); 263 | ``` 264 | 265 | *Mostly pure conventions. `Function#bind` is [relatively slow](http://jsperf.com/bind-vs-scope-perf) compared to lexical `thisArg` scoping, but lexical scoping is ugly and harder to read. Arrow functions desugar to lexical scoping and are a good compromise. In some cases the following snippet can be useful:* 266 | 267 | ```js 268 | const scope = (fn, thisArg) => (...params) => fn.apply(thisArg, ...params); 269 | ``` 270 | 271 | ## Function parameters 272 | 273 | - A parameter **must not** be named `arguments`. 274 | 275 | - Parameters **should** BE explicitly typechecked in a `__DEV__` block. They CAN be documented in addition. 276 | 277 | - ES6 default parameter value **should** be used when applicable. 278 | 279 | - Destructuring parameter syntax **should** be used when applicable. 280 | 281 | - Explicit variadic expansion **should** be used over ES6 rest syntax. If you really need true dynamic variadic functions, ES6 rest syntax **must** be used, not `arguments` inspection. 282 | 283 | ```js 284 | // bad 285 | function sum() { 286 | let sum = 0; 287 | for(let k = 0; k < arguments.length; k++) { 288 | sum += arguments[k]; 289 | } 290 | return sum; 291 | } 292 | 293 | // good 294 | function sum(a = 0, b = 0, c = 0, d = 0, e = 0, f = 0, g = 0, h = 0, i = 0) { 295 | return a + b + c + d + e + f + g + h + i; 296 | } 297 | 298 | // acceptable 299 | function sum(...rest) { 300 | return rest.reduce((x, y) => x + y, 0); 301 | } 302 | ``` 303 | 304 | - Object parameters (with default values) **should** be used for options parameters. Boolean parameters **must not** be used. 305 | 306 | ```js 307 | // bad 308 | function divide(a, b, shouldCheckForZero = false ) { 309 | 310 | } 311 | 312 | // good 313 | function divide(a, b, { shouldCheckForZero = false } = {}) { 314 | 315 | } 316 | ``` 317 | *ES6 destructuring assignment is a very powerful construct which considerably simplifies the use of object-as-hashes params. It also enables a kind of named parameters pattern. While named parameters are usually more readable than unnamed parameters, it really shines against the [boolean trap](http://ariya.ofilabs.com/2011/08/hall-of-api-shame-boolean-trap.html) antipattern.* 318 | 319 | ## Properties 320 | 321 | - Dot/subscript notation **must** be used consistently. 322 | 323 | - Dot notation **should** be used when possible. 324 | 325 | ```js 326 | // bad 327 | t.x = 3; 328 | t['y'] = 4; 329 | 330 | // good 331 | t['x'] = 3; 332 | t['y'] = 4; 333 | 334 | // better 335 | t.x = 3; 336 | t.y = 4; 337 | ``` 338 | 339 | *Mostly pure convention. Dot notation is usually easier to read, but sometimes it's just not possible (for dynamic keys and special characters). In this case, consistency is best.* 340 | 341 | ## Operators 342 | 343 | - Short-hand operators `+=`-like and `++`-like operators **must not** be used. Also, consider refactoring to get rid of the underlying `let`. 344 | 345 | ```js 346 | let n = 0; 347 | // bad 348 | n += 1; 349 | n++; 350 | 351 | // good 352 | n = n + 1; 353 | ``` 354 | 355 | - Non-strict comparison operators `==` or `!=` **must not** be used. Strict comparison operators `===` or `!==` **must** be used instead. 356 | 357 | - Boolean force-casting `!!expr` **should not** be used. `expr` **should** BE used directly, unless you specifically care about leaking values in a function call or a return value. 358 | 359 | ```js 360 | // bad 361 | if(!!expr) { 362 | ... 363 | } 364 | 365 | // good 366 | if(expr) { 367 | ... 368 | } 369 | 370 | // acceptable to prevent leaking values 371 | someUntrustedFunction(!!expr); 372 | ``` 373 | 374 | *Pure convention for shorthand operators. Shorthand operators are marginally harder to read, but its really more of a convention. Boolean force-casting is useless and convoluted, unless you specifically care about the value of the expression leaking (besides its boolean value), but this doesn't matter in `if`-like constructs, only in function calls or return values.* 375 | 376 | ## Comments 377 | 378 | - `/* ... */`-style **must** be used for non-jsdoc multiline comments. 379 | 380 | - `/** ... */`-style **must** be used for jsdoc comments. 381 | 382 | - Be very careful when using trailing `//`. For single-line comments, comment on the previous line of whatever you're commenting. 383 | 384 | *Pure convention.* 385 | 386 | ## Whitespace 387 | 388 | - Tab characters **must not** be used. Ever. Tabs are evil. Don't use them. 389 | 390 | - Soft-spacing 2-characters **must** be used. 391 | 392 | ```js 393 | // bad 394 | if(true) { 395 | return 42; 396 | } 397 | 398 | // good 399 | if(true) { 400 | return 42; 401 | } 402 | ``` 403 | 404 | - 1 space **must** be used before the leading brace `{`. 405 | 406 | ```js 407 | // bad 408 | if(true){ 409 | ... 410 | } 411 | 412 | // good 413 | if(true) { 414 | ... 415 | } 416 | ``` 417 | 418 | - 1 space **must** be used before the ending brace `}` in single-line object literals or function declaration. 419 | 420 | ```js 421 | // bad 422 | function answer() { return 42;} 423 | const a = { a: 42}; 424 | 425 | // good 426 | function answer() { return 42; } 427 | const a = { a: 42 }; 428 | ``` 429 | 430 | - Space **must not** be used before the leading bracket `[` or the ending bracket `]` in single-line array literals. 431 | 432 | ```js 433 | // bad 434 | const a = [ 1, 2 ]; 435 | 436 | // good 437 | const a = [1, 2]; 438 | ``` 439 | 440 | - Space **must not** be used before the leading paren `(`. 441 | 442 | ```js 443 | // bad 444 | if (true) { 445 | ... 446 | } 447 | 448 | // good 449 | if(true) { 450 | ... 451 | } 452 | ``` 453 | 454 | - Space **must not** be used between `function` and `*` when defining generator. Space **must** BE used between `*` and the function name when defining named generators. 455 | 456 | ```js 457 | // bad 458 | function *g() { 459 | 460 | } 461 | 462 | // good 463 | function* g() { 464 | 465 | } 466 | ``` 467 | 468 | - Space **must not** be used between `*` and the generator name when using the shorthand generator method syntax. 469 | 470 | ```js 471 | // bad 472 | const a = { 473 | * g() { 474 | ... 475 | } 476 | }; 477 | 478 | // good 479 | const a = { 480 | *g() { 481 | ... 482 | } 483 | }; 484 | ``` 485 | 486 | - Spaces **must** BE used between infix operators. 487 | 488 | ```js 489 | // bad 490 | const a = b+c; 491 | const a= b + c; 492 | 493 | // good 494 | const a = b + c; 495 | ``` 496 | 497 | - Files **must** end with a single newline character. 498 | 499 | - Leading dot and proper indentation **must** be used for method chaining. 500 | 501 | ```js 502 | // bad 503 | a.then(...). 504 | then(...). 505 | catch(...); 506 | 507 | a.then(...) 508 | .then(...) 509 | .catch(...); 510 | 511 | // good 512 | a.then(...) 513 | .then(...) 514 | .then(...) 515 | .catch(...); 516 | ``` 517 | 518 | *Pure convention. Also, tabs are evil. Don't use them.* 519 | 520 | ## Blocks 521 | 522 | - Braces **must** BE used for blocks, even single-statement blocks. Only exception is 1-expression arrow functions. 523 | 524 | ```js 525 | // bad 526 | if(true) 527 | return 42; 528 | if(true) return 42; 529 | const id = (x) => { return x; }; 530 | 531 | // good 532 | if(true) { return 42; } 533 | if(true) { 534 | return 42; 535 | } 536 | const id = (x) => x; 537 | const id = (x) => { 538 | return x; 539 | }; 540 | const id = (x) => 541 | functionCall(x) 542 | ; 543 | ``` 544 | 545 | *Always-braces is easier to maintain: one can add or remove statements/instructions without having to maintain the braces. Also easier to scan.* 546 | 547 | ## Commas 548 | 549 | - Trailing commas **must** be used for multiline literals, and **must not** be used for single-line literals. 550 | 551 | ```js 552 | // bad 553 | const a = { a: 42, b: 43, }; 554 | const a = { 555 | a: 42, 556 | b: 42 557 | }; 558 | 559 | // good 560 | const a = { a: 42, b: 42 }; 561 | const a = { 562 | a: 42, 563 | b: 43, 564 | }; 565 | ``` 566 | 567 | *Trailing commas are easier to maintain; one can add or remove properties without having to maintain the commas. Also produces cleaner git diffs.* 568 | 569 | ## Semicolons 570 | 571 | - Trailing semicolons **must** be used, even when they are not strictly required. 572 | 573 | ```js 574 | // bad 575 | function id(x) { return x } 576 | 577 | // good 578 | function id(x) { return x; } 579 | 580 | // actually better 581 | const id = (x) => x; 582 | ``` 583 | 584 | *Easier to maintain; one can add or remove statements without having to maintain the semicolon. Also produces cleaner git diffs. Avoid subtle bugs.* 585 | 586 | ## if/else construct 587 | 588 | - `if`/`else if`/`else` **must** be preceded by a newline. 589 | 590 | ```js 591 | // bad 592 | if(...) { 593 | ... 594 | } else if(...) { 595 | ... 596 | } else { 597 | ... 598 | } 599 | 600 | // good 601 | if(...) { 602 | ... 603 | } 604 | else if { 605 | ... 606 | } 607 | else { 608 | ... 609 | } 610 | ``` 611 | 612 | *Easier to read and refactor.* 613 | 614 | ## Ternary operator 615 | 616 | - Ternary operator (`?:`) **should** be avoided. 617 | 618 | - It **must not** be used if: 619 | 620 | - The whole expression cannot fit on one line; 621 | 622 | - The expression involve other ternary operators; 623 | 624 | - The members of the expression are too complex to keep it readable. 625 | 626 | ```js 627 | // bad 628 | const foo = bar === baz ? aFunctionWithALongNameCalledIfTheFirstExpressionIsTrue() 629 | : aFunctionWithALongNameCalledIfTheFirstExpressionIsFalse(); 630 | 631 | // bad 632 | const foo = bar === baz 633 | ? aFunctionWithALongNameCalledIfTheFirstExpressionIsTrue() 634 | : aFunctionWithALongNameCalledIfTheFirstExpressionIsFalse(); 635 | 636 | // bad 637 | const foo = bar === baz ? 638 | aFunctionWithALongNameCalledIfTheFirstExpressionIsTrue() : 639 | aFunctionWithALongNameCalledIfTheFirstExpressionIsFalse(); 640 | 641 | // bad 642 | const foo = fooBar(bar + qux) * qux ? fooBar(barFoo({ bar })[qux]).foo : fooBar(barFoo({ qux })[foo]).baz; 643 | 644 | // bad 645 | const foo = qux ? (bar ? qux : baz) : bar; 646 | 647 | // acceptable 648 | const foo = bar === baz ? bar + 1 : baz - 1; 649 | 650 | // good 651 | const foo = bar ? baz : qux; 652 | ``` 653 | 654 | # switch construct 655 | 656 | - `switch` construct **should not** be used unless you are absolutely confident you are optimizing a super hot function which your JS engine can't optimize by itself. `if/else if/else` **should** be used instead. 657 | 658 | *When two constructs are equivalent, pick one and stick to it. Also, missing `break` bugs are very tedious.* 659 | 660 | # for in, for of 661 | 662 | - `for in` and `for of` **should not** be used unless you are absolutely confident you are optimizing a super hot function which your JS engine can't optimize by itself. `forEach/map` **should** be used instead. 663 | 664 | *When two constructs are equivalent, pick one and stick to it. Also, missing `hasOwnProperty` check bugs are very tedious. `for` loops are very rarely needed in ES6 code where `forEach/map` and arrow functions can achieve almost every conceivable looping pattern and are easier to reason about. In edge cases where optimization is actually needed, it can be helpful though.* 665 | 666 | ## Method short notation 667 | 668 | - ES6 method short notation **should** be used when applicable. 669 | 670 | ```js 671 | // bad 672 | const a = { 673 | f: function() { 674 | ... 675 | } 676 | } 677 | 678 | // good 679 | const a = { 680 | f() { 681 | 682 | } 683 | } 684 | ``` 685 | 686 | *Less clutter and easier to maintain.* 687 | 688 | ## ES6 modules 689 | 690 | - ES6 modules **must** be used, `require`-style module **must not** be used. Destructuring assignment **should** be used when applicable. 691 | 692 | ```js 693 | // bad 694 | const moduleA = require('moduleA'); 695 | const func1 = moduleA.func1; 696 | const func2 = moduleA.func2; 697 | 698 | // bad 699 | import * as moduleA from 'moduleA'; 700 | const func1 = moduleA.func1; 701 | const func2 = moduleA.func2; 702 | 703 | // good 704 | import { func1, func2 } from 'moduleA'; 705 | ``` 706 | 707 | *More standards-friendly and easier to change the module implementation backend (eg. CommonJS/AMD) at the transpiler level.* 708 | 709 | ## undefined 710 | 711 | - `undefined` **must not** be used, `void 0` **must** be used instead. 712 | 713 | ```js 714 | // bad 715 | if(x === undefined) { 716 | ... 717 | } 718 | 719 | // good 720 | if(x === void 0) { 721 | ... 722 | } 723 | ``` 724 | 725 | *Pure convention. Also `void 0` looks more l33t.* 726 | 727 | ## Object extension and reshaping 728 | 729 | - Object reshaping **should** be avoided by declaring their shape early with `null` values, with the notable exceptions of Objects used as maps (but in this case, ES6 Map/Set/WeakMap/WeapSet is often more suited). 730 | 731 | - `delete` **should not** be used, with the notable exceptions of Objects used as maps (see above). Settings the value to `null` **should** be used to explicitly remove a reference for garbage collection. 732 | 733 | - In case reshaping is unavoidable, `Object.assign` **must** be used. In particular, `Object.assign` **must** be used to define prototype properties on ES6 classes. 734 | 735 | - In the particular case of a constructor function, an object **should** not be reshaped after the end of the constructor. 736 | 737 | - `__proto__` **should not** be used. `Object.setPrototypeOf` **should** be used instead, but with great care. 738 | 739 | ```js 740 | // bad 741 | const a = {}; 742 | a.x = 3; 743 | delete a.x; 744 | 745 | // if reshape unavoidable 746 | const a = {}; 747 | Object.assign(a, { x: 3 }); 748 | 749 | // good 750 | const a = { x: null }; 751 | a.x = 3; 752 | a.x = null; 753 | 754 | 755 | function F() { ... } 756 | 757 | // bad 758 | F.prototype.staticA = 43; 759 | F.prototype.staticB = 44; 760 | F.prototype.protoProp = null; 761 | F.prototype.method = function() { 762 | ... 763 | } 764 | 765 | // good 766 | Object.assign(F.prototype, { 767 | staticA: 43, 768 | staticB: 44, 769 | protoProp: null, 770 | method() { 771 | ... 772 | } 773 | }); 774 | ``` 775 | 776 | *Object reshaping highly impacts performance on frequently created/used Objects. While negligible on less frequently used Objects (eg. singletons), it is preferable to be consistent and always avoid reshaping Objects. Objects used as hashes (maps) will often be reshaped anyway so this cannot be avoided, but in this case consider using ES6 Map/Set/WeakMap/WeakSet. Usage of Object.assign instead of multiple property assignment is marginally less efficient, but is easier to maintain and enables using the ES6 method short notation. Mutating the `__proto__` has huge performance implications and should be used with extreme care.* 777 | 778 | 779 | ## Classes 780 | 781 | - Class names **must** be `PascalCased`. 782 | 783 | - When defined, `constructor` **should** be the first method of a class definition. 784 | 785 | - The order of class methods definitions **should** always be: 786 | 787 | - `constructor` 788 | 789 | - public `get/set` accessors, grouped by name, 790 | 791 | - public methods, 792 | 793 | - private `get/set` accessors (with a `_` prefix), grouped by name, 794 | 795 | - private methods (with a `_` prefix), 796 | 797 | - public static methods, 798 | 799 | - private static methods (with a `_` prefix). 800 | 801 | - Prototype properties **should** be defined immediately after the class definition and use `Object.assign` and **should not** contain methods (set them in the class definition directly). 802 | 803 | - If your transpiler or environment support ES7 class properties, prototype properties of classes **should not** be used (use class properties instead). 804 | 805 | ```js 806 | class Foo extends Bar { 807 | // If your transpiler or environment support ES7 class properties: 808 | bax = null; 809 | baw = 1337; 810 | 811 | constructor() { // constructor 812 | ... 813 | } 814 | 815 | get baz() { // public getter 816 | ... 817 | } 818 | 819 | set baz(val) { // public setter 820 | ... 821 | } 822 | 823 | doFoo() { // public method 824 | ... 825 | } 826 | 827 | get _baz() { // private getter 828 | ... 829 | } 830 | 831 | set _baz(val) { // private setter 832 | ... 833 | } 834 | 835 | _doFoo() { // private method 836 | ... 837 | } 838 | 839 | // If your transpiler or environment support ES7 class properties: 840 | static theFoo = 'theBar'; 841 | 842 | static doFoo() { // public static method 843 | ... 844 | } 845 | 846 | static _doFoo() { // private static method 847 | ... 848 | } 849 | } 850 | 851 | // If your transpiler or environment doesn't support ES7 class properties: 852 | Object.assign(Foo.prototype, { // prototype properties 853 | bax: null, 854 | baw: 1337, 855 | }); 856 | 857 | Object.assign(Foo, { // static properties 858 | theFoo: 'theBar', 859 | }); 860 | ``` 861 | 862 | *Mostly pure conventions. Public API are closer to the beginning of the declaration, making it easier to read. Also produces cleaner diffs since private methods are more susceptible to changes than public methods. The prototype properties must be defined outside of the `class` block due to ES6 limitations, but it should be very close to the class definition.* 863 | 864 | 865 | ## Proxies 866 | 867 | - Proxies **must not** be used at the moment. 868 | 869 | *There is no production-ready transpilation for ES6 Proxies. In addition, they may introduce questionable black magic.* 870 | 871 | ## Promises 872 | 873 | - `Promise#then` **must not** be used with 2 parameters. `Promise#catch` **must** be used instead. 874 | 875 | - `Promise#try` **should** be used for `Promise`-returning function, instead of `return Promise.resolve`/`return Promise.reject`. 876 | 877 | ```js 878 | // bad 879 | p.then(() => { 880 | ... 881 | }, () => { 882 | ... 883 | }); 884 | 885 | function f() { 886 | if(...) { 887 | return Promise.resolve(...); 888 | } 889 | else { 890 | return Promise.reject(...); 891 | } 892 | } 893 | 894 | // good 895 | p.then(() => { 896 | 897 | }) 898 | .catch(() => { 899 | 900 | }); 901 | 902 | function f() { 903 | return Promise.try(() => { 904 | if(...) { 905 | return ...; 906 | } 907 | else { 908 | throw ...; 909 | } 910 | }); 911 | } 912 | ``` 913 | 914 | *`Promise` is a relatively low-level/interoperaribility spec. The excellent [`bluebird`](https://github.com/petkaantonov/bluebird/blob/master/API.md) implements higher-level primitives that implement the hardest thing to do right with Promises: error propagation. In addition to its excellent performance (outperforming native Promises in most cases), it will most likely help you avoid common pitfalls with Promises.* 915 | 916 | ## Tail calls 917 | 918 | - Tail call optimization **should not** be assumed except for simple recursive functions (self-referencing functions). Tail call optimization **must not** be relied on for complex recursive function (eg. mutually recursive functions). 919 | 920 | ```js 921 | // bad 922 | function odd(n) { 923 | if(n === 0) { 924 | return false; 925 | } 926 | if(n === 1) { 927 | return true; 928 | } 929 | return !even(n-1); 930 | } 931 | 932 | function even(n) { 933 | if(n === 0) { 934 | return true; 935 | } 936 | if(n === 1) { 937 | return false; 938 | } 939 | return !odd(n-1); 940 | } 941 | 942 | // good 943 | function factorial(n) { 944 | function factorialLoop(n, acc) { 945 | if(n === 1) { 946 | return acc; 947 | } 948 | else { 949 | return factorialLoop(n - 1, n*acc); 950 | } 951 | } 952 | return factorialLoop(n, 1); 953 | } 954 | ``` 955 | 956 | *Tail calls are very hard to transpile efficiently. It is only partially supported by babel.* 957 | 958 | ## Generators 959 | 960 | - Generators **must** contain at least one `yield` statement. If not, consider using a `Promise`-returning function instead. 961 | 962 | - Generator short-hand definition **must** be used where applicable. 963 | 964 | ```js 965 | // bad 966 | const a = { 967 | g: function*() { 968 | ... 969 | } 970 | } 971 | 972 | // good 973 | const a = { 974 | *g() { 975 | ... 976 | } 977 | } 978 | ``` 979 | 980 | *Pure convention. Also, `Promise` and `yield` are interoperable, see [`Promise#coroutine`](https://github.com/petkaantonov/bluebird/blob/master/API.md#generators).* 981 | -------------------------------------------------------------------------------- /postgres.md: -------------------------------------------------------------------------------- 1 | 2 | ## Uppercase and lowercase ## 3 | ##### Use uppercase for statements, operators and keywords. 4 | ```sql 5 | -- bad 6 | SELECT * FROM foo order by bar; 7 | 8 | -- good 9 | SELECT * FROM foo ORDER BY bar; 10 | ``` 11 | 12 | ##### Use lowercase for functions. 13 | ```sql 14 | -- bad 15 | SELECT COUNT(*) FROM foo; 16 | 17 | -- good 18 | SELECT count(*) FROM foo; 19 | ``` 20 | 21 | ##### Use lowercase for types. 22 | ```sql 23 | -- bad 24 | CREATE TABLE foo(bar INTEGER, baz TEXT); 25 | 26 | -- good 27 | CREATE TABLE foo(bar integer, baz text); 28 | ``` 29 | 30 | ## Quotation marks ## 31 | ##### Do not use quotation marks for identifiers, unless you are defining a new type (which needs camelCase notation). 32 | ```sql 33 | -- bad 34 | UPDATE "foo" SET "bar" = x; 35 | 36 | -- good 37 | UPDATE foo SET bar = x; 38 | 39 | -- good 40 | CREATE TYPE foo AS ( 41 | "fooId" integer, 42 | "title" text, 43 | "parentId" integer 44 | ); 45 | ``` 46 | 47 | ## Operators ## 48 | ##### Use same difference operator as other languages. 49 | ```sql 50 | -- bad 51 | SELECT baz FROM foo WHERE bar <> baz; 52 | 53 | -- good 54 | SELECT bar FROM foo WHERE bar != baz; 55 | ``` 56 | 57 | ##### Do not use double pipes for concatenation to avoid `NULL` values. 58 | ```sql 59 | -- bad 60 | SELECT 'foo' || 'bar'; 61 | 62 | -- good 63 | SELECT concat('foo', 'bar'); 64 | ``` 65 | 66 | ##### Do not use casting operator when not needed. 67 | ```sql 68 | -- bad 69 | SELECT cast('bar' AS integer); 70 | 71 | -- good 72 | SELECT 'bar'::integer; 73 | 74 | -- only for immutable functions 75 | CREATE FUNCTION foo() RETURNS text IMMUTABLE AS $$ 76 | SELECT integer 'bar'; 77 | $$ LANGUAGE sql ; 78 | ``` 79 | 80 | ## Arrays ## 81 | ##### Use proper array declaration. 82 | ```sql 83 | -- bad 84 | SELECT '{1, 2, 3 + 4}'; 85 | 86 | -- bad 87 | SELECT array[1,2,3+4]; 88 | 89 | -- good 90 | SELECT ARRAY[1, 2, 3 + 4]; 91 | ``` 92 | 93 | ## Functions parameters ## 94 | ##### Use explicit parameters (with `in_` or `out_` prefix) instead of positional parameters. 95 | ```sql 96 | -- bad 97 | CREATE FUNCTION foo(text) RETURNS text AS $$ 98 | SELECT $1; 99 | $$ LANGUAGE sql; 100 | 101 | -- bad 102 | CREATE FUNCTION foo(bar text) RETURNS text AS $$ 103 | SELECT bar; 104 | $$ LANGUAGE sql; 105 | 106 | -- good 107 | CREATE FUNCTION foo(in_bar text) RETURNS text AS $$ 108 | SELECT in_bar; 109 | $$ LANGUAGE sql; 110 | ``` 111 | 112 | ##### Parameters with a default value must be declared with the `DEFAULT` keyword. 113 | ```sql 114 | -- bad 115 | CREATE FUNCTION foo(in_bar text = 'bar') RETURNS text AS $$ 116 | SELECT in_bar; 117 | $$ LANGUAGE sql; 118 | 119 | -- good 120 | CREATE FUNCTION foo(in_bar text DEFAULT 'bar') RETURNS text AS $$ 121 | SELECT in_bar; 122 | $$ LANGUAGE sql; 123 | ``` 124 | 125 | ##### Always specify parameters' name on non-standard function calls. 126 | ```sql 127 | CREATE FUNCTION foo(in_a integer, in_b integer, in_c integer) RETURNS text AS $$ 128 | SELECT in_a; 129 | SELECT in_b; 130 | SELECT in_c; 131 | $$ LANGUAGE sql; 132 | 133 | -- bad 134 | SELECT foo(1, 2, 3); 135 | 136 | -- good 137 | SELECT foo(in_a := 1, in_b := 2, in_c := 3); 138 | 139 | -- if needed 140 | SELECT foo(in_c := 3, in_a := 1, in_b := 2); 141 | ``` 142 | 143 | ## Tables names ## 144 | ##### Use singular words for table names. 145 | ```sql 146 | --bad 147 | SELECT foo FROM bars; 148 | 149 | -- good 150 | SELECT foo FROM bar; 151 | ``` 152 | 153 | ##### Use the `join_table_name_with_table_name` pattern to define JOIN tables' name. 154 | ```sql 155 | CREATE TABLE foo(foo_id serial); 156 | CREATE TABLE bar(bar_id serial); 157 | 158 | -- wrong 159 | CREATE TABLE foo_bar(foo_id serial, bar_id serial); 160 | 161 | -- good 162 | CREATE TABLE join_foo_with_bar(foo_id serial, bar_id serial); 163 | ``` 164 | 165 | ##### Use the `ref_table_name` pattern to define REFERENCE tables' name. 166 | ```sql 167 | -- bad 168 | CREATE TABLE nationality(nationality_id serial, title text); 169 | 170 | -- good 171 | CREATE TABLE ref_nationality(nationality_id serial, title text); 172 | ``` 173 | 174 | ##### Use the `rt_type` pattern to define new types. 175 | ```sql 176 | -- bad 177 | CREATE TYPE foo AS ("barBaz" integer); 178 | 179 | -- good 180 | CREATE TYPE rt_foo AS ("barBaz" integer); 181 | ``` 182 | 183 | ## Column names ## 184 | ##### Prefix table id with table name. 185 | ```sql 186 | -- bad 187 | CREATE TABLE foo(id serial); 188 | 189 | -- good 190 | CREATE TABLE foo(foo_id serial); 191 | ``` 192 | 193 | ##### Prefix denormalized column with `denorm_`. 194 | ```sql 195 | CREATE TABLE person ( 196 | birth_date timestamp, 197 | denorm_age integer, 198 | ); 199 | ``` 200 | 201 | ## Table constraints ## 202 | ##### `NULL` and `NOT NULL` constraints must be declared into the table declaration without explicit column reference. 203 | ```sql 204 | -- bad 205 | CREATE TABLE foo(bar integer, NOT NULL (bar)); 206 | 207 | -- good 208 | CREATE TABLE foo(bar integer NOT NULL); 209 | ``` 210 | 211 | ##### As they are unique, `PRIMARY KEY` constraints must be named based on the `pkey_*table*` pattern. 212 | ```sql 213 | -- bad 214 | ALTER TABLE foo ADD CONSTRAINT foo_foo_id_pkey PRIMARY KEY (foo_id); 215 | 216 | -- good 217 | ALTER TABLE foo ADD CONSTRAINT pkey_foo PRIMARY KEY (foo_id); 218 | ``` 219 | 220 | ##### Other constraints must be explicitly named based on the `*key*_*table*_on_*column*(_and_*column*)` pattern. 221 | Keys are: `fkey` for `FOREIGN KEY`, `key` for `UNIQUE`, `check` for `CHECK`. 222 | ```sql 223 | CREATE TABLE foo(foo_id serial, bar_id integer); 224 | 225 | -- bad 226 | ALTER TABLE foo ADD CONSTRAINT foo_bar_id_fkey FOREIGN KEY bar_id REFERENCES bar(bar_id); 227 | 228 | -- good 229 | ALTER TABLE foo ADD CONSTRAINT fkey_foo_on_bar_id FOREIGN KEY bar_id REFERENCES bar(bar_id); 230 | 231 | -- good 232 | ALTER TABLE foo ADD CONSTRAINT check_foo_on_foo_id_and_bar_id CHECK (foo_id > bar_id); 233 | ``` 234 | 235 | ## Indexes ## 236 | ##### Indexes must be explicitly named based on the `idx_*table*_on_*column*(_and_*column*)` pattern. 237 | ```sql 238 | -- bad 239 | CREATE INDEX ON foo(bar, baz); 240 | 241 | -- good 242 | CREATE INDEX idx_foo_on_bar_and_baz ON foo(bar, baz); 243 | ``` 244 | 245 | ## Statements ## 246 | ##### Always specify the needed columns. 247 | ```sql 248 | -- bad 249 | SELECT * FROM foo; 250 | 251 | -- good 252 | SELECT foo_id, bar_id, creation_date FROM foo; 253 | ``` 254 | 255 | ##### Specify table columns when inserting even if it is set to default. 256 | ```sql 257 | CREATE TABLE foo(a, b default 0, c, d default 1); 258 | 259 | -- bad 260 | INSERT INTO foo VALUES (1, 2, 3, 4); 261 | 262 | -- bad 263 | INSERT INTO foo(a, c) VALUES (1, 3); 264 | 265 | -- good 266 | INSERT INTO foo(a, b, c, d) VALUES (1, 2, 3, 4); 267 | 268 | -- good 269 | INSERT INTO foo(a, b, c, d) VALUES (1, default, 3, default); 270 | ``` 271 | 272 | ##### Do not use `NATURAL JOIN` and `JOIN USING`, [it is unreliable](http://www.databasesoup.com/2013/08/fancy-sql-monday-on-vs-natural-join-vs.html?showComment=1376400799327#c2740364122038525231). Use instead `JOIN ON`. 273 | ```sql 274 | -- bad 275 | SELECT baz FROM foo NATURAL JOIN bar; 276 | 277 | -- bad 278 | SELECT baz FROM foo JOIN bar USING(foo_id); 279 | 280 | -- good 281 | SELECT baz FROM foo JOIN bar ON foo.foo_id = bar.foo_id; 282 | ``` 283 | 284 | ##### Do not use unnecessary `INNER` and `OUTER` statements when using `JOIN` 285 | ```sql 286 | -- bad 287 | SELECT baz FROM foo INNER JOIN bar ON ...; 288 | 289 | -- good 290 | SELECT baz FROM foo JOIN bar ON ...; 291 | ``` 292 | 293 | ##### Do not use `NOT IN`, [it never matches if there is but a single `NULL` in the list](http://stackoverflow.com/a/2246793/2554269). 294 | ```sql 295 | -- bad 296 | SELECT foo_id FROM foo WHERE foo_id NOT IN (SELECT foo_id FROM bar); 297 | 298 | -- good 299 | SELECT foo_id FROM foo WHERE NOT EXISTS (SELECT foo_id FROM bar); 300 | ``` 301 | 302 | ##### Separate columns and their aliases 303 | ```sql 304 | -- bad 305 | SELECT f.bar FROM foo f; 306 | 307 | -- good 308 | SELECT f.bar FROM foo AS f; 309 | ``` 310 | 311 | ## Spaces and parentheses ## 312 | ##### Do not use space before parentheses when writing one-line code unless it is following a keyword. 313 | ```sql 314 | -- bad 315 | CREATE TABLE foo (); 316 | INSERT INTO bar (baz) VALUES (1); 317 | INSERT INTO bar(baz) VALUES(1); 318 | CREATE FUNCTION foo_bar (in_a text) ...; 319 | 320 | -- good 321 | CREATE TABLE foo(); 322 | INSERT INTO bar(baz) VALUES (1); 323 | CREATE FUNCTION foo_bar(in_a text) ...; 324 | ``` 325 | 326 | ##### Use space before parentheses and comma dangle at line end when using multi-line code. 327 | ```sql 328 | -- bad 329 | CREATE table foo 330 | ( 331 | a, 332 | b, 333 | c 334 | ); 335 | 336 | -- bad 337 | CREATE table foo ( 338 | a 339 | , b 340 | , c 341 | ); 342 | 343 | -- good 344 | CREATE TABLE foo ( 345 | a, 346 | b, 347 | c 348 | ); 349 | ``` 350 | 351 | ## Functions indentation ## 352 | ##### Respect proper function indentation, name the `$$` block and use multi-line parameters only if needed. 353 | ```sql 354 | -- good 355 | CREATE FUNCTION foo(in_a text, in_b integer) 356 | RETURNS integer 357 | VOLATILE SECURITY INVOKER 358 | AS $body$ 359 | SELECT foo_id FROM foo WHERE bar = in_a AND baz = in_b; 360 | $body$ LANGUAGE sql; 361 | 362 | -- if needed 363 | CREATE FUNCTION foo ( 364 | in_a text, 365 | in_b integer 366 | ) 367 | RETURNS integer 368 | VOLATILE SECURITY INVOKER 369 | AS $body$ 370 | SELECT foo_id FROM foo WHERE bar = in_a AND baz = in_b; 371 | $body$ LANGUAGE sql; 372 | ``` 373 | 374 | ## Queries indentation ## 375 | ##### Respect proper query indentation. Each statements must be right-aligned for the same depth. Each depth must be aligned one space behind its parent and is independent in terms of statements' right-alignment. 376 | ```sql 377 | -- good 378 | SELECT foo_id 379 | FROM foo 380 | WHERE foo_id IN ( 381 | SELECT foo_id 382 | FROM bar 383 | ); 384 | 385 | -- good 386 | SELECT f.data, 387 | f.item, 388 | f.category 389 | FROM foo AS f 390 | JOIN bar AS b 391 | ON f.id = b.id 392 | WHERE f.data > b.data 393 | AND f.item > 0 394 | GROUP BY f.category 395 | HAVING count(*) > 0 396 | ORDER BY f.rank 397 | LIMIT 10; 398 | 399 | -- good 400 | WITH foo_with AS ( 401 | SELECT name, 402 | sum(price) AS total_price, 403 | product 404 | FROM foo 405 | GROUP BY name 406 | ), 407 | bar_with AS ( 408 | SELECT name 409 | FROM foo_with 410 | WHERE total_foo > ( 411 | SELECT total / 10 412 | FROM bar 413 | ) 414 | ); 415 | 416 | -- good 417 | ALTER TABLE foo 418 | ADD CONSTRAINT fkey_foo_on_bar_id 419 | FOREIGN KEY (bar_id) 420 | REFERENCES bar(bar_id), 421 | ADD CONSTRAINT check_foo_on_baz 422 | CHECK (baz > 10); 423 | ``` 424 | --------------------------------------------------------------------------------