eslint-config-punchcard
Punchcard CMS ESLint Config
The place to start for the Punchcard JavaScript Style Guide is the Airbnb JavaScript Style Guide. We follow the Airbnb Style Guide with the following modifications, presented below. Most modifications are clarifications of existing rules where Airbnb does not specify anything, or expanding the existing rules for additional usecases we have.
Best Practices
Curly Brace Conventions
Curly braces should never omitted, even when they are optional.
Rule | Settings | Type |
---|---|---|
curly | [2] |
error |
//////////////////////////////// OK//////////////////////////////if foo foo++; while bar ; if foo ; else ; //////////////////////////////// Not OK//////////////////////////////if foo foo++; /*error Expected { after 'if' condition.*/ while bar /*error Expected { after 'while' condition.*/ ; if foo /*error Expected { after 'else'.*/ ; else ;
Enforce Newline Before and After Dot
New lines must come before dots for properties
Rule | Settings | Type |
---|---|---|
dot-location | [2, 'property'] |
error |
//////////////////////////////// OK//////////////////////////////var foo = objectproperty;var bar = objectproperty; //////////////////////////////// Not OK//////////////////////////////var foo = object /*error Expected dot to be on same line as property.*/property;
No Invalid This
No usage of this
outside of classes or class-like objects
Rule | Settings | Type |
---|---|---|
no-invalid-this | [2] |
error |
//////////////////////////////// OK////////////////////////////// { //this is in a legacy style constructor. thisa = 0; ;} { // this is in a constructor. thisa = 0; ; } var obj = { // this is in a method (this function is on object literal). thisa = 0; }; //////////////////////////////// Not OK//////////////////////////////thisa = 0; /*error Unexpected `this`.*/; /*error Unexpected `this`.*/ { thisa = 0; /*error Unexpected `this`.*/ ; /*error Unexpected `this`.*/}; { thisa = 0; /*error Unexpected `this`.*/ ; /*error Unexpected `this`.*/}
No Iterator
No usage of the __iterator__
property on item's prototype.
Rule | Settings | Type |
---|---|---|
no-iterator | [2] |
error |
//////////////////////////////// OK//////////////////////////////var __iterator__ = foo; // Not using the `__iterator__` property. //////////////////////////////// Not OK//////////////////////////////Fooprototype { /*error Reserved name '__iterator__'.*/ return this;}; foo {}; /*error Reserved name '__iterator__'.*/ foo"__iterator__" = {}; /*error Reserved name '__iterator__'.*/
Node
Return After Callback
Always return a callback()
if it's called outside the main function body.
Rule | Settings | Type |
---|---|---|
callback-return | [2] |
error |
//////////////////////////////// OK////////////////////////////// { if err return ; ;} //////////////////////////////// Not OK////////////////////////////// { if err ; /*error Expected return with your callback function.*/ ;}
Global Require
All require()
statements must be at the top-level module scope.
Rule | Settings | Type |
---|---|---|
global-require | [2] |
error |
//////////////////////////////// OK//////////////////////////////// all these variations of require() are ok;var y = ;var z;z = ; // requiring a module and using it in a function is okvar fs = ; { fs} //////////////////////////////// Not OK//////////////////////////////// calling require() inside of a function is not allowed { var fs = ; /*error Unexpected require().*/ fs} // conditional requires like this are also not allowedif DEBUG ; /*error Unexpected require().*/ // a require() in a switch statement is also flagged
Handle Callback Error
All errors must be handled in function callbacks and not allowed to fall through or "get eaten".
Rule | Settings | Type |
---|---|---|
handle-callback-err | [2] |
error |
//////////////////////////////// OK////////////////////////////// { if err console; ;} { if err {}} //////////////////////////////// Not OK////////////////////////////// { /*error Expected error to be handled.*/ ;}
No Mixed Requires
Do not mix require requires statements. Group core module
requires separate from requires from file module
requires, installed module
requires, computed
module requires, uninitialized
declarations, and any other
declarations.
Rule | Settings | Type |
---|---|---|
no-mixed-requires | [2, true] |
error |
//////////////////////////////// OK//////////////////////////////// only non-require declarationsvar foo = 42 bar = 'baz'; // always valid regardless of grouping because all declarations are of the same typevar foo = bar = baz = ; //////////////////////////////// Not OK//////////////////////////////// invalid because of mixed types "core" and "file"var fs = /*error Do not mix core, module, file and computed requires.*/ async = ; // invalid because of mixed types "file" and "unknown"var foo = /*error Do not mix core, module, file and computed requires.*/ bar = ;
Disallow New Require
Disallow the use of new
directly with a require()
statement.
Rule | Settings | Type |
---|---|---|
no-new-require | [2] |
error |
//////////////////////////////// OK//////////////////////////////var AppHeader = ; //////////////////////////////// Not OK//////////////////////////////var appHeader = 'app-header'; /*error Unexpected use of new with require.*/
No Path Concat
Require the use of path.join()
to create paths, disallowing simple string concatenation to do so, when using __dirname
and __filename
Rule | Settings | Type |
---|---|---|
no-path-concat | [2] |
error |
//////////////////////////////// OK//////////////////////////////var fullPath = dirname + '/foo.js'; var fullPath = path; var fullPath = path; //////////////////////////////// Not OK//////////////////////////////var fullPath = __dirname + '/foo.js'; /*error Use path.join() or path.resolve() instead of + to create paths.*/ var fullPath = __filename + '/foo.js'; /*error Use path.join() or path.resolve() instead of + to create paths.*/
No Process Exit
Disallow using process.exit()
.
Rule | Settings | Type |
---|---|---|
no-process-exit | [2] |
error |
//////////////////////////////// OK//////////////////////////////Process;var exit = processexit; //////////////////////////////// Not OK//////////////////////////////process; /*error Don't use process.exit(); throw an error instead.*/process; /*error Don't use process.exit(); throw an error instead.*/
Style
Brace Style
Always use Stroustrup style bracing, and never allow a single single line blocks.
Rule | Settings | Type |
---|---|---|
brace-style | [2, 'stroustrup', {'allowSingleLine': true}] |
error |
//////////////////////////////// OK////////////////////////////// { return true;} if foo ;else ; //////////////////////////////// Not OK//////////////////////////////{ return true;} if foo ; else ; if foo ;
Camelcase
Always require camelCase naming, even in property names
Rule | Settings | Type |
---|---|---|
camelcase | [2, {'properties': 'always'}] |
error |
//////////////////////////////// OK//////////////////////////////var myFavoriteColor = "#112C85";var _myFavoriteColor = "#112C85";var myFavoriteColor_ = "#112C85";var MY_FAVORITE_COLOR = "#112C85";var foo = barbaz_boom;var foo = qux: barbaz_boom ; obj; //////////////////////////////// Not OK//////////////////////////////var my_favorite_color = "#112C85"; /*error Identifier 'my_favorite_color' is not in camel case.*/ { /*error Identifier 'do_something' is not in camel case.*/ // ...} obj { /*error Identifier 'do_something' is not in camel case.*/ // ...}; var obj = my_pref: 1 /*error Identifier 'my_pref' is not in camel case.*/;
Consistent This
If you need to track this
for nested context, always use a variable named _this
;
Rule | Settings | Type |
---|---|---|
consistent-this | [2, '_this'] |
error |
//////////////////////////////// OK//////////////////////////////var _this = this;var self = 64;var that = 42;var that; _this = this; foobar = this; //////////////////////////////// Not OK//////////////////////////////var _this = 42; /*error Designated alias '_this' is not assigned to 'this'.*/ var that = this; /*error Unexpected alias 'that' for 'this'.*/ _this = 42; /*error Designated alias '_this' is not assigned to 'this'.*/ that = this; /*error Unexpected alias 'that' for 'this'.*/
Function Style
Always declare functions as expressions, never as a declaration
Rule | Settings | Type |
---|---|---|
func-style | [2, 'expression'] |
error |
//////////////////////////////// OK//////////////////////////////var { // ...}; const bar = {}; //////////////////////////////// Not OK////////////////////////////// { /*error Expected a function expression.*/ // ...}
Indentation
Always indent with two spaces. When writing multiple declarations of var
and let
with one keyword, and switch
statement keywords, indent twice.
Rule | Settings | Type |
---|---|---|
indent | [2, 2, {'VariableDeclarator': {'var': 2}, 'SwitchCase': 2}] |
error |
//////////////////////////////// OK//////////////////////////////var foo bar baz; //////////////////////////////// Not OK//////////////////////////////var foo bar baz;
Linebreak Style
Always use unix
linebreaks
Rule | Settings | Type |
---|---|---|
linebreak-style | [2, 'unix'] |
error |
//////////////////////////////// OK//////////////////////////////var a = 'a' // \n b = 'b'; // \n// \n {// \n // do stuff \n}// \n //////////////////////////////// Not OK//////////////////////////////var a = 'a'; // \r\n /*error Expected linebreaks to be 'LF' but found 'CRLF'.*/ var a = 'a' // \r\n /*error Expected linebreaks to be 'LF' but found 'CRLF'.*/ b = 'b'; // \n
Lines Around Comments
Always require a new line before a comment. Comments starting new blocks, objects, or arrays do not need a new line before them
Rule | Settings | Type |
---|---|---|
lines-around-comment | [2, {'beforeBlockComment': true, 'beforeLineComment': true, 'allowBlockStart': true, 'allowObjectStart': true, 'allowArrayStart': true}] |
error |
//////////////////////////////// OK//////////////////////////////var { // This comment is OK ; /* This comment is OK too */ ; // This comment is awesome ; const waldo = /* This is cool */ shirt: stripes ; let garfield = // As is this 'fat' 'cat' ;} //////////////////////////////// Not OK//////////////////////////////var { ; /* This comment is Not OK */ ; // This comment is not awesome ;}
Max Depth
Be cautious of nesting expressions more than 4 levels deep
Rule | Settings | Type |
---|---|---|
max-depth | [1, 4] |
warning |
//////////////////////////////// Okay//////////////////////////////var { for ;; // Nested 1 deep. if true // Nested 2 deep. if true // Nested 3 deep. if true // Nested 4 deep } //////////////////////////////// Not OK//////////////////////////////var { for ;; if true if true if true if true /*error Blocks are nested too deeply (4).*/ }
One Variable Declaration
Use only a single declaration when creating var
and let
variables. Always create individual const
variables.
Rule | Settings | Type |
---|---|---|
one-var | [2, {'var': 'always', 'let': 'never', 'const': 'never'}] |
error |
//////////////////////////////// OK//////////////////////////////var { var bar baz; let qux; const waldo;} //////////////////////////////// Not OK//////////////////////////////var { var bar; var baz; /*error Combine this with the previous 'let' statement.*/ let qux /*error Split 'let' declarations into multiple statements.*/ quarx; const waldo; /*error Split 'const' declarations into multiple statements.*/}
Padded Blocks
Never pad your blocks with beginning or ending spaces
Rule | Settings | Type |
---|---|---|
padded-blocks | [2, 'never'] |
error |
//////////////////////////////// OK//////////////////////////////if a ; //////////////////////////////// Not OK//////////////////////////////if a /*error Block must not be padded by blank lines.*/ ; /*error Block must not be padded by blank lines.*/ if a /*error Block must not be padded by blank lines.*/ ; /*error Block must not be padded by blank lines.*/ if a /*error Block must not be padded by blank lines.*/ ; /*error Block must not be padded by blank lines.*/
Quote Properties
Keep property quoting consistent within an object.
Rule | Settings | Type |
---|---|---|
quote-props | [2, 'consistent'] |
error |
//////////////////////////////// OK//////////////////////////////var object = 'foo': 'bar' 'baz': 42 'qux': true; var object = foo: 'bar' baz: 42 qux: true; // Need quotes for everything because `qux-lorem` requires quotesvar object = 'foo': 'bar' 'baz': 42 'qux-lorem': true; //////////////////////////////// Not OK//////////////////////////////var object = foo: 'bar' baz: 42 'qux-lorem': true; var object = foo: 'bar' baz: 42 'qux': true;
Space Before Keywords
Always include a space before a keyword if it is not the first item in a line.
Rule | Settings | Type |
---|---|---|
space-before-keywords | [2, 'always'] |
error |
//////////////////////////////// OK//////////////////////////////if foo // ... else {} {} <Foo onClick= {} /> for let foo of 'bar' 'baz' 'qux' {} //////////////////////////////// Not OK//////////////////////////////if foo // ...else {} /*error Missing space before keyword "else".*/ const foo = 'bar';let baz = 'qux'; /*error Missing space before keyword "let".*/ var {} /*error Missing space before keyword "function".*/ { if foo return; /*error Missing space before keyword "return".*/}
Spaces Before/After Unary Operations
Always include a space around unary word operators (such as new
, delete
, typeof
, void
, yield
), but not around nonword operators (such as -
, +
, --
, ++
, !
, !!
).
Rule | Settings | Type |
---|---|---|
space-unary-ops | [2, {'words': true, 'nonwords': false}] |
error |
//////////////////////////////// OK//////////////////////////////// Word unary operator "delete" is followed by a whitespace.delete foobar; // Word unary operator "new" is followed by a whitespace.; // Word unary operator "void" is followed by a whitespace.void 0; // Unary operator "++" is not followed by whitespace.++foo; // Unary operator "--" is not preceeded by whitespace.foo--; // Unary operator "-" is not followed by whitespace.-foo; // Unary operator "+" is not followed by whitespace.+"3"; //////////////////////////////// Not OK//////////////////////////////typeof!foo; /*error Unary word operator "typeof" must be followed by whitespace.*/ voidfoo:0; /*error Unary word operator "void" must be followed by whitespace.*/ newfoo0; /*error Unary word operator "new" must be followed by whitespace.*/ deletefoobar; /*error Unary word operator "delete" must be followed by whitespace.*/ { 0 /*error Unary word operator "yield" must be followed by whitespace.*/} ++ foo; /*error Unexpected space after unary operator "++".*/ foo --; /*error Unexpected space before unary operator "--".*/ - foo; /*error Unexpected space after unary operator "-".*/ + "3"; /*error Unexpected space after unary operator "+".*/
Space
Always require a space after an initializing a comment with //
or /*
. Characters -
, +
, /
, and *
do not need any spacing and are exceptions. Characters =
and !
do not need a space before them, but need a space after them, and are markers.
Rule | Settings | Type |
---|---|---|
spaced-comment | [2, 'always', {'exceptions': ['-', '+', '/', '*'], 'markers': ['=', '!']}] |
error |
//////////////////////////////// OK////////////////////////////// //--------------// Comment block//-------------- //++++++++++++++// Comment block//++++++++++++++ ////////////////// Comment block//////////////// /**************** * Comment block ****************/ //= This is a comment with a marker//! This is a comment with a marker //////////////////////////////// Not OK////////////////////////////// //=This is a comment with a marker /*error Expected space or tab after // in comment.*///!This is a comment with a marker /*error Expected space or tab after // in comment.*/ /*-+-+-+-+-+-+-+*/ /*error Expected space or tab after /* in comment.*/// Comment block/*-+-+-+-+-+-+-+*/ /*error Expected space or tab after /* in comment.*/ /*------++++++++*/ /*error Expected exception block, space or tab after /* in comment.*//* Comment block *//*------++++++++*/ /*error Expected exception block, space or tab after /* in comment.*/
Summary of Changes
Best Practices
Rule | Settings | Type |
---|---|---|
curly | [2] |
error |
dot-location | [2, 'property'] |
error |
no-invalid-this | [2] |
error |
no-iterator | [2] |
error |
Node
Rule | Settings | Type |
---|---|---|
callback-return | [2] |
error |
global-require | [2] |
error |
handle-callback-err | [2] |
error |
no-mixed-requires | [2, true] |
error |
no-new-require | [2] |
error |
no-path-concat | [2] |
error |
no-process-exit | [2] |
error |
Style
Rule | Settings | Type |
---|---|---|
block-spacing | [2, 'always'] |
error |
brace-style | [2, 'stroustrup', {'allowSingleLine': true}] |
error |
camelcase | [2, {'properties': 'always'}] |
error |
consistent-this | [2, '_this'] |
error |
func-style | [2, 'expression'] |
error |
indent | [2, 2, {'VariableDeclarator': {'var': 2}, 'SwitchCase': 2}] |
error |
linebreak-style | [2, 'unix'] |
error |
lines-around-comment | [2, {'beforeBlockComment': true, 'beforeLineComment': true, 'allowBlockStart': true, 'allowObjectStart': true, 'allowArrayStart': true}] |
error |
max-depth | [1, 4] |
warning |
one-var | [2, {'var': 'always', 'let': 'never', 'const': 'never'}] |
error |
padded-blocks | [2, 'never'] |
error |
quote-props | [2, 'consistent'] |
error |
space-before-keywords | [2, 'always'] |
error |
space-unary-ops | [2, {'words': true, 'nonwords': false}] |
error |
spaced-comment | [2, 'always', {'exceptions': ['-', '+', '/', '*'], 'markers': ['=', '!']}] |
error |