├── test ├── fixtures │ ├── node-env.js │ ├── camelcase.js │ ├── no-unused-vars.js │ ├── semi.js │ ├── indent.js │ ├── hapi-scope-start.js │ ├── brace-style.js │ ├── indent-switch-case.js │ └── no-shadow-relaxed.js └── index.js ├── .travis.yml ├── .gitignore ├── package.json ├── LICENSE ├── README.md └── lib └── index.js /test/fixtures/node-env.js: -------------------------------------------------------------------------------- 1 | var Fs = require('fs'); 2 | 3 | module.exports = Fs; 4 | -------------------------------------------------------------------------------- /test/fixtures/camelcase.js: -------------------------------------------------------------------------------- 1 | var foo_bar = '123'; 2 | var barBaz = '456'; 3 | 4 | return foo_bar + barBaz; 5 | -------------------------------------------------------------------------------- /test/fixtures/no-unused-vars.js: -------------------------------------------------------------------------------- 1 | var internals = {}; 2 | var internals2 = {}; 3 | var bar = function (foo) { 4 | 5 | }; 6 | 7 | return bar; 8 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: node_js 3 | node_js: 4 | - "0.10" 5 | - "0.12" 6 | - "4" 7 | - "iojs-v1" 8 | - "iojs-v2" 9 | - "iojs" 10 | -------------------------------------------------------------------------------- /test/fixtures/semi.js: -------------------------------------------------------------------------------- 1 | module.exports.foo = function () { 2 | 3 | return 42 4 | }; 5 | 6 | module.exports.bar = function () { 7 | 8 | return 85; 9 | }; 10 | -------------------------------------------------------------------------------- /test/fixtures/indent.js: -------------------------------------------------------------------------------- 1 | module.exports.foo = function (value) { 2 | 3 | return value + 1; 4 | }; 5 | 6 | 7 | module.exports.foo = function (value) { 8 | 9 | return value + 1; 10 | }; 11 | -------------------------------------------------------------------------------- /test/fixtures/hapi-scope-start.js: -------------------------------------------------------------------------------- 1 | var foo = function () { 2 | return 'there should be a blank line before this line'; 3 | }; 4 | 5 | var bar = function () { 6 | 7 | return 'no lint errors'; 8 | }; 9 | 10 | foo(); 11 | bar(); 12 | -------------------------------------------------------------------------------- /test/fixtures/brace-style.js: -------------------------------------------------------------------------------- 1 | var foo = true; 2 | var bar = 0; 3 | 4 | if (foo) { 5 | bar = 1; 6 | } else { 7 | bar = 2; 8 | } 9 | 10 | if (foo) { 11 | bar = 3; 12 | } 13 | else { 14 | bar = 4; 15 | } 16 | 17 | return bar; 18 | -------------------------------------------------------------------------------- /test/fixtures/indent-switch-case.js: -------------------------------------------------------------------------------- 1 | var foo = 'foo'; 2 | var result = 0; 3 | 4 | switch (foo) { 5 | case 'foo': 6 | result = 1; 7 | break; 8 | 9 | case 'bar': 10 | result = 2; 11 | break; 12 | case 'baz': 13 | result = 3; 14 | break; 15 | } 16 | 17 | return result; 18 | -------------------------------------------------------------------------------- /test/fixtures/no-shadow-relaxed.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-unused-vars */ 2 | 3 | 4 | // Declare internals 5 | 6 | var internals = {}; 7 | 8 | 9 | module.exports.foo = function (value) { 10 | 11 | var top = function (err) { 12 | 13 | var inner = function (err) { 14 | 15 | return value; 16 | }; 17 | }; 18 | 19 | top(); 20 | }; 21 | 22 | 23 | module.exports.bar = function (value) { 24 | 25 | var top = function (res) { 26 | 27 | var inner = function (res) { 28 | 29 | return value; 30 | }; 31 | }; 32 | 33 | top(); 34 | }; 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Directory for instrumented libs generated by jscoverage/JSCover 11 | lib-cov 12 | 13 | # Coverage directory used by tools like istanbul 14 | coverage 15 | 16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 17 | .grunt 18 | 19 | # node-waf configuration 20 | .lock-wscript 21 | 22 | # Compiled binary addons (http://nodejs.org/api/addons.html) 23 | build/Release 24 | 25 | # Dependency directory 26 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git 27 | node_modules 28 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "eslint-config-hapi", 3 | "version": "3.0.2", 4 | "description": "Shareable ESLint config for the hapi ecosystem", 5 | "author": "Continuation Labs (http://continuation.io/)", 6 | "main": "lib/index.js", 7 | "homepage": "https://github.com/continuationlabs/eslint-config-hapi", 8 | "repository": { 9 | "type": "git", 10 | "url": "https://github.com/continuationlabs/eslint-config-hapi.git" 11 | }, 12 | "bugs": { 13 | "url": "https://github.com/continuationlabs/eslint-config-hapi/issues" 14 | }, 15 | "license": "MIT", 16 | "scripts": { 17 | "test": "lab -v -t 100 -a code" 18 | }, 19 | "peerDependencies": { 20 | "eslint-plugin-hapi": "1.x.x" 21 | }, 22 | "devDependencies": { 23 | "code": "1.x.x", 24 | "eslint": "1.x.x", 25 | "eslint-plugin-hapi": "1.x.x", 26 | "lab": "6.x.x" 27 | }, 28 | "keywords": [ 29 | "hapi", 30 | "lint", 31 | "eslint", 32 | "eslintconfig" 33 | ] 34 | } 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Continuation Labs 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # eslint-config-hapi 2 | 3 | [![Current Version](https://img.shields.io/npm/v/eslint-config-hapi.svg)](https://www.npmjs.org/package/eslint-config-hapi) 4 | [![Build Status via Travis CI](https://travis-ci.org/continuationlabs/eslint-config-hapi.svg?branch=master)](https://travis-ci.org/continuationlabs/eslint-config-hapi) 5 | ![Dependencies](http://img.shields.io/david/continuationlabs/eslint-config-hapi.svg) 6 | ![devDependencies](http://img.shields.io/david/dev/continuationlabs/eslint-config-hapi.svg) 7 | 8 | Shareable ESLint config for the hapi ecosystem. To use in your project, add `eslint-config-hapi` and [`eslint-plugin-hapi`](https://github.com/continuationlabs/eslint-plugin-hapi) to your `package.json`, then in your ESLint configuration add: 9 | 10 | ``` 11 | { 12 | "extends": "eslint-config-hapi" 13 | } 14 | ``` 15 | 16 | ESLint will automatically insert the `eslint-config-`, so technically, you can just write `"extends": "hapi"`. 17 | 18 | **Note:** `eslint-plugin-hapi` is a plugin containing custom hapi linting rules. It is a peer dependency because of the way ESLint handles shareable configs that include plugins and custom rules (see [eslint/eslint#3458](https://github.com/eslint/eslint/issues/3458) and [eslint/eslint#2518](https://github.com/eslint/eslint/issues/2518) for more background). 19 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: ['eslint-plugin-hapi'], 3 | env: { 4 | node: true, 5 | es6: true 6 | }, 7 | rules: { 8 | 'camelcase': 0, 9 | 'consistent-return': 0, 10 | 'vars-on-top': 0, 11 | 'one-var': 0, 12 | 'strict': 0, 13 | 'new-cap': 0, 14 | 'no-console': 0, 15 | 'no-constant-condition': 0, 16 | 'no-empty': 0, 17 | 'no-native-reassign': 0, 18 | 'no-underscore-dangle': 0, 19 | 'no-undef': 0, 20 | 'no-process-exit': 0, 21 | 'no-use-before-define': 0, 22 | 'no-unused-expressions': 0, 23 | 'no-regex-spaces': 0, 24 | 'no-catch-shadow': 0, 25 | 'strict': 0, 26 | 'handle-callback-err': 0, 27 | 'no-lonely-if': 0, 28 | 'no-shadow': 0, 29 | 'brace-style': [1, 'stroustrup'], 30 | 'no-unused-vars': [1, { vars: 'all', varsIgnorePattern: '^internals$', 'args': 'none' }], 31 | 'hapi/no-shadow-relaxed': [1, { 'ignore': ['err', 'done'] }], 32 | 'hapi/hapi-capitalize-modules': [1, 'global-scope-only'], 33 | 'hapi/hapi-scope-start': 1, 34 | 'array-bracket-spacing': 1, 35 | 'dot-notation': 1, 36 | 'eol-last': 1, 37 | 'no-trailing-spaces': 1, 38 | 'no-eq-null': 1, 39 | 'no-extend-native': 1, 40 | 'no-redeclare': 1, 41 | 'no-loop-func': 1, 42 | 'yoda': [1, 'never'], 43 | 'sort-vars': 1, 44 | 'quotes': [2, 'single'], 45 | 'consistent-this': [2, 'self'], 46 | 'func-style': [2, 'expression'], 47 | 'new-parens': 2, 48 | 'no-array-constructor': 2, 49 | 'no-new-object': 2, 50 | 'no-spaced-func': 2, 51 | 'no-mixed-spaces-and-tabs': 2, 52 | 'space-after-keywords': 2, 53 | 'semi': [2, 'always'], 54 | 'semi-spacing': [2, { 'before': false, 'after': true }], 55 | 'space-infix-ops': 2, 56 | 'space-return-throw-case': 2, 57 | 'space-unary-ops': [1, { 'words': true, 'nonwords': false }], 58 | 'eqeqeq': 2, 59 | 'curly': [2, 'all'], 60 | 'no-eval': 2, 61 | 'no-else-return': 2, 62 | 'no-return-assign': 2, 63 | 'no-new-wrappers': 2, 64 | 'comma-dangle': [2, 'never'], 65 | 'no-sparse-arrays': 2, 66 | 'no-ex-assign': 2, 67 | 'indent': [2, 4, { 'SwitchCase': 1 }], 68 | 'space-before-function-paren': 2, 69 | 'func-style': [2, 'expression'], 70 | 'object-curly-spacing': [2, 'always'] 71 | } 72 | }; 73 | -------------------------------------------------------------------------------- /test/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var Fs = require('fs'); 3 | var Path = require('path'); 4 | var Code = require('code'); 5 | var ESLint = require('eslint'); 6 | var Lab = require('lab'); 7 | var Config = require('../lib'); 8 | var CLIEngine = ESLint.CLIEngine; 9 | 10 | // Test shortcuts 11 | var lab = exports.lab = Lab.script(); 12 | var expect = Code.expect; 13 | var describe = lab.describe; 14 | var it = lab.it; 15 | 16 | Code.settings.truncateMessages = false; 17 | 18 | function getLinter() { 19 | return new CLIEngine({ 20 | useEslintrc: false, 21 | baseConfig: Config 22 | }); 23 | } 24 | 25 | function lintFile(file) { 26 | var cli = getLinter(); 27 | var data = Fs.readFileSync(Path.join(__dirname, file), 'utf8'); 28 | 29 | return cli.executeOnText(data); 30 | } 31 | 32 | function lintString(str) { 33 | var cli = getLinter(); 34 | 35 | return cli.executeOnText(str); 36 | } 37 | 38 | describe('eslint-config-hapi', function () { 39 | it('enforces stroustrup style braces', function (done) { 40 | var output = lintFile('fixtures/brace-style.js'); 41 | var results = output.results[0]; 42 | 43 | expect(output.errorCount).to.equal(0); 44 | expect(output.warningCount).to.equal(1); 45 | expect(results.errorCount).to.equal(0); 46 | expect(results.warningCount).to.equal(1); 47 | 48 | var msg = results.messages[0]; 49 | 50 | expect(msg.ruleId).to.equal('brace-style'); 51 | expect(msg.severity).to.equal(1); 52 | expect(msg.message).to.equal('Closing curly brace appears on the same line as the subsequent block.'); 53 | expect(msg.line).to.equal(6); 54 | expect(msg.column).to.equal(8); 55 | expect(msg.nodeType).to.equal('BlockStatement'); 56 | expect(msg.source).to.equal('} else {'); 57 | done(); 58 | }); 59 | 60 | it('enforces four space indentation', function (done) { 61 | var output = lintFile('fixtures/indent.js'); 62 | var results = output.results[0]; 63 | 64 | expect(output.errorCount).to.equal(1); 65 | expect(output.warningCount).to.equal(0); 66 | expect(results.errorCount).to.equal(1); 67 | expect(results.warningCount).to.equal(0); 68 | 69 | var msg = results.messages[0]; 70 | 71 | expect(msg.ruleId).to.equal('indent'); 72 | expect(msg.severity).to.equal(2); 73 | expect(msg.message).to.equal('Expected indentation of 4 space characters but found 2.'); 74 | expect(msg.line).to.equal(3); 75 | expect(msg.column).to.equal(3); 76 | expect(msg.nodeType).to.equal('ReturnStatement'); 77 | expect(msg.source).to.equal(' return value + 1;'); 78 | done(); 79 | }); 80 | 81 | it('enforces case indentation in switch statements', function (done) { 82 | var output = lintFile('fixtures/indent-switch-case.js'); 83 | var results = output.results[0]; 84 | 85 | expect(output.errorCount).to.equal(5); 86 | expect(output.warningCount).to.equal(0); 87 | expect(results.errorCount).to.equal(5); 88 | expect(results.warningCount).to.equal(0); 89 | 90 | var msg = results.messages[0]; 91 | 92 | expect(msg.ruleId).to.equal('indent'); 93 | expect(msg.severity).to.equal(2); 94 | expect(msg.message).to.equal('Expected indentation of 4 space characters but found 0.'); 95 | expect(msg.line).to.equal(9); 96 | expect(msg.column).to.equal(1); 97 | expect(msg.nodeType).to.equal('SwitchCase'); 98 | expect(msg.source).to.equal('case \'bar\':'); 99 | 100 | msg = results.messages[1]; 101 | 102 | expect(msg.ruleId).to.equal('indent'); 103 | expect(msg.severity).to.equal(2); 104 | expect(msg.message).to.equal('Expected indentation of 8 space characters but found 4.'); 105 | expect(msg.line).to.equal(10); 106 | expect(msg.column).to.equal(5); 107 | expect(msg.nodeType).to.equal('ExpressionStatement'); 108 | expect(msg.source).to.equal(' result = 2;'); 109 | 110 | msg = results.messages[2]; 111 | 112 | expect(msg.ruleId).to.equal('indent'); 113 | expect(msg.severity).to.equal(2); 114 | expect(msg.message).to.equal('Expected indentation of 8 space characters but found 4.'); 115 | expect(msg.line).to.equal(11); 116 | expect(msg.column).to.equal(5); 117 | expect(msg.nodeType).to.equal('BreakStatement'); 118 | expect(msg.source).to.equal(' break;'); 119 | 120 | msg = results.messages[3]; 121 | 122 | expect(msg.ruleId).to.equal('indent'); 123 | expect(msg.severity).to.equal(2); 124 | expect(msg.message).to.equal('Expected indentation of 8 space characters but found 4.'); 125 | expect(msg.line).to.equal(13); 126 | expect(msg.column).to.equal(5); 127 | expect(msg.nodeType).to.equal('ExpressionStatement'); 128 | expect(msg.source).to.equal(' result = 3;'); 129 | 130 | msg = results.messages[4]; 131 | 132 | expect(msg.ruleId).to.equal('indent'); 133 | expect(msg.severity).to.equal(2); 134 | expect(msg.message).to.equal('Expected indentation of 8 space characters but found 4.'); 135 | expect(msg.line).to.equal(14); 136 | expect(msg.column).to.equal(5); 137 | expect(msg.nodeType).to.equal('BreakStatement'); 138 | expect(msg.source).to.equal(' break;'); 139 | 140 | done(); 141 | }); 142 | 143 | it('enforces semicolon usage', function (done) { 144 | var output = lintFile('fixtures/semi.js'); 145 | var results = output.results[0]; 146 | 147 | expect(output.errorCount).to.equal(1); 148 | expect(output.warningCount).to.equal(0); 149 | expect(results.errorCount).to.equal(1); 150 | expect(results.warningCount).to.equal(0); 151 | 152 | var msg = results.messages[0]; 153 | 154 | expect(msg.ruleId).to.equal('semi'); 155 | expect(msg.severity).to.equal(2); 156 | expect(msg.message).to.equal('Missing semicolon.'); 157 | expect(msg.line).to.equal(3); 158 | expect(msg.column).to.equal(14); 159 | expect(msg.nodeType).to.equal('ReturnStatement'); 160 | expect(msg.source).to.equal(' return 42'); 161 | done(); 162 | }); 163 | 164 | it('enforces hapi/hapi-scope-start', function (done) { 165 | var output = lintFile('fixtures/hapi-scope-start.js'); 166 | var results = output.results[0]; 167 | 168 | expect(output.errorCount).to.equal(0); 169 | expect(output.warningCount).to.equal(1); 170 | expect(results.errorCount).to.equal(0); 171 | expect(results.warningCount).to.equal(1); 172 | 173 | var msg = results.messages[0]; 174 | 175 | expect(msg.ruleId).to.equal('hapi/hapi-scope-start'); 176 | expect(msg.severity).to.equal(1); 177 | expect(msg.message).to.equal('Missing blank line at beginning of function.'); 178 | expect(msg.line).to.equal(1); 179 | expect(msg.column).to.equal(11); 180 | expect(msg.nodeType).to.equal('FunctionExpression'); 181 | expect(msg.source).to.equal('var foo = function () {'); 182 | done(); 183 | }); 184 | 185 | it('enforces hapi/no-shadow-relaxed', function (done) { 186 | var output = lintFile('fixtures/no-shadow-relaxed.js'); 187 | var results = output.results[0]; 188 | 189 | expect(output.errorCount).to.equal(0); 190 | expect(output.warningCount).to.equal(1); 191 | expect(results.errorCount).to.equal(0); 192 | expect(results.warningCount).to.equal(1); 193 | 194 | var msg = results.messages[0]; 195 | 196 | expect(msg.ruleId).to.equal('hapi/no-shadow-relaxed'); 197 | expect(msg.severity).to.equal(1); 198 | expect(msg.message).to.equal('res is already declared in the upper scope.'); 199 | expect(msg.line).to.equal(27); 200 | expect(msg.column).to.equal(31); 201 | expect(msg.nodeType).to.equal('Identifier'); 202 | expect(msg.source).to.equal(' var inner = function (res) {'); 203 | done(); 204 | }); 205 | 206 | it('enforces no-unused-vars', function (done) { 207 | var output = lintFile('fixtures/no-unused-vars.js'); 208 | var results = output.results[0]; 209 | 210 | expect(output.errorCount).to.equal(0); 211 | expect(output.warningCount).to.equal(1); 212 | expect(results.errorCount).to.equal(0); 213 | expect(results.warningCount).to.equal(1); 214 | 215 | var msg = results.messages[0]; 216 | 217 | expect(msg.ruleId).to.equal('no-unused-vars'); 218 | expect(msg.severity).to.equal(1); 219 | expect(msg.message).to.equal('"internals2" is defined but never used'); 220 | expect(msg.line).to.equal(2); 221 | expect(msg.column).to.equal(5); 222 | expect(msg.nodeType).to.equal('Identifier'); 223 | expect(msg.source).to.equal('var internals2 = {};'); 224 | done(); 225 | }); 226 | 227 | it('uses the node environment', function (done) { 228 | var output = lintFile('fixtures/node-env.js'); 229 | var results = output.results[0]; 230 | 231 | expect(output.errorCount).to.equal(0); 232 | expect(output.warningCount).to.equal(0); 233 | expect(results.errorCount).to.equal(0); 234 | expect(results.warningCount).to.equal(0); 235 | expect(results.messages).to.deep.equal([]); 236 | done(); 237 | }); 238 | 239 | it('uses the ES6 environment', function (done) { 240 | // Do this as a string to prevent problems during testing on old versions of Node 241 | var output = lintString('module.exports = `__filename = ${__filename}`;\n'); 242 | var results = output.results[0]; 243 | 244 | expect(output.errorCount).to.equal(0); 245 | expect(output.warningCount).to.equal(0); 246 | expect(results.errorCount).to.equal(0); 247 | expect(results.warningCount).to.equal(0); 248 | expect(results.messages).to.deep.equal([]); 249 | done(); 250 | }); 251 | 252 | it('does not enforce the camelcase lint rule', function (done) { 253 | var output = lintFile('fixtures/camelcase.js'); 254 | var results = output.results[0]; 255 | 256 | expect(output.errorCount).to.equal(0); 257 | expect(output.warningCount).to.equal(0); 258 | expect(results.errorCount).to.equal(0); 259 | expect(results.warningCount).to.equal(0); 260 | expect(results.messages).to.deep.equal([]); 261 | done(); 262 | }); 263 | }); 264 | --------------------------------------------------------------------------------