diff --git a/.gitignore b/.gitignore index 493e11a2e90b..27a29bf0b62a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,9 @@ /config/* /logs/* /node_modules -/gulp-cache +/eslint-cache /chat-plugins/private.js npm-debug.log -.eslintcache* # boilerplate # ############### diff --git a/.travis.yml b/.travis.yml index 17d805ad3cb7..a0299460fe97 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,4 +5,4 @@ node_js: cache: directories: - node_modules - - gulp-cache + - eslint-cache diff --git a/app.js b/app.js index 61e006b8c523..d33e6bd3e466 100644 --- a/app.js +++ b/app.js @@ -108,9 +108,12 @@ try { Config.port = cloudenv.get('PORT', Config.port); } catch (e) {} -if (require.main === module && process.argv[2] && parseInt(process.argv[2])) { - Config.port = parseInt(process.argv[2]); - Config.ssl = null; +if (require.main === module && process.argv[2]) { + let port = parseInt(process.argv[2]); // eslint-disable-line radix + if (port) { + Config.port = port; + Config.ssl = null; + } } /********************************************************* diff --git a/battle-engine.js b/battle-engine.js index 8f5b7d99db4b..9d9a89b5bb1d 100644 --- a/battle-engine.js +++ b/battle-engine.js @@ -55,7 +55,7 @@ let Battle, BattleSide, BattlePokemon; let Battles = Object.create(null); -require('./repl.js').start('battle-engine-', process.pid, function (cmd) { return eval(cmd); }); // eslint-disable-line no-eval +require('./repl.js').start('battle-engine-', process.pid, function (cmd) { return eval(cmd); }); // Receive and process a message sent using Simulator.prototype.send in // another process. @@ -129,7 +129,7 @@ process.on('message', function (message) { } } else if (data[1] === 'eval') { try { - eval(data[2]); // eslint-disable-line no-eval + eval(data[2]); } catch (e) {} } } diff --git a/chat-plugins/info.js b/chat-plugins/info.js index ce5e3fd02cc1..310f8abd9568 100644 --- a/chat-plugins/info.js +++ b/chat-plugins/info.js @@ -14,7 +14,7 @@ const RESULTS_MAX_LENGTH = 10; -let commands = exports.commands = { +let commands = exports.commands = { // eslint-disable-line no-unused-vars ip: 'whois', rooms: 'whois', diff --git a/chat-plugins/jeopardy.js b/chat-plugins/jeopardy.js index 45ca344a7978..e35e1cc24e07 100644 --- a/chat-plugins/jeopardy.js +++ b/chat-plugins/jeopardy.js @@ -51,8 +51,9 @@ let JeopardyQuestions = (function () { JeopardyQuestions.prototype.export = function (category, start, end) { let data = []; - for (let q = start; q < end; ++q) + for (let q = start; q < end; ++q) { data.push(this.grid[category][q]); + } return data; }; JeopardyQuestions.prototype.import = function (category, start, end, data) { diff --git a/cidr.js b/cidr.js index f0200772c2c7..b61b0a229de2 100644 --- a/cidr.js +++ b/cidr.js @@ -65,6 +65,6 @@ let checker = exports.checker = function (cidr) { }; }; -let check = exports.check = function (cidr, ip) { +let check = exports.check = function (cidr, ip) { // eslint-disable-line no-unused-vars return checker(cidr)(ip); }; diff --git a/commands.js b/commands.js index cb61aad33854..076e68013b2e 100644 --- a/commands.js +++ b/commands.js @@ -22,7 +22,7 @@ const MAX_REASON_LENGTH = 300; const MUTE_LENGTH = 7 * 60 * 1000; const HOURMUTE_LENGTH = 60 * 60 * 1000; -let commands = exports.commands = { +let commands = exports.commands = { // eslint-disable-line no-unused-vars version: function (target, room, user) { if (!this.canBroadcast()) return; @@ -2048,9 +2048,11 @@ let commands = exports.commands = { if (!this.broadcasting) this.sendReply('||>> ' + target); try { + /* eslint-disable no-unused-vars */ let battle = room.battle; let me = user; this.sendReply('||<< ' + eval(target)); + /* eslint-enable no-unused-vars */ } catch (e) { this.sendReply('||<< error: ' + e.message); let stack = '||' + ('' + e.stack).replace(/\n/g, '\n||'); diff --git a/dev-tools/eslint/config-base.js b/dev-tools/eslint/config-base.js new file mode 100644 index 000000000000..49bf3bf8d559 --- /dev/null +++ b/dev-tools/eslint/config-base.js @@ -0,0 +1,167 @@ +const os = require('os'); + +module.exports = { + "env": { + "node": true, + "es6": true + }, + "globals": { + "Config": false, "Monitor": false, "toId": false, "Tools": false, "LoginServer": false, + "Users": false, "Rooms": false, "Verifier": false, "CommandParser": false, "Simulator": false, + "Tournaments": false, "Dnsbl": false, "Cidr": false, "Sockets": false, "TeamValidator": false, "Ladders": false + }, + "rules": { + "comma-dangle": [2, "never"], + "no-cond-assign": [2, "except-parens"], + "no-console": 0, + "no-constant-condition": 0, + "no-control-regex": 0, + "no-debugger": 2, + "no-dupe-args": 2, + "no-dupe-keys": 2, + "no-duplicate-case": 1, + "no-empty-character-class": 2, + "no-empty": 0, + "no-ex-assign": 2, + "disallow-extra-boolean-casts": 0, + "no-extra-parens": 0, + "no-extra-semi": 2, + "no-func-assign": 2, + "no-inner-declarations": 2, + "no-invalid-regexp": 2, + "no-irregular-whitespace": 2, + "no-negated-in-lhs": 2, + "no-obj-calls": 2, + "no-regex-spaces": 2, + "no-sparse-arrays": 2, + "no-unexpected-multiline": 2, + "no-unreachable": 2, + "use-isnan": 2, + "valid-jsdoc": 0, + "valid-typeof": 2, + + "block-scoped-var": 2, + "complexity": 0, + "consistent-return": 0, + "curly": [2, "multi-line", "consistent"], + "default-case": 0, + "dot-location": [2, "property"], + "dot-notation": 0, + "eqeqeq": 2, + "no-caller": 2, + "no-case-declarations": 0, + "no-div-regex": 2, + "no-else-return": 0, + "no-empty-label": 2, + "no-empty-pattern": 1, + "no-eval": 0, + "no-implied-eval": 2, + "no-extend-native": 2, + "no-extra-bind": 1, + "no-fallthrough": 2, + "no-floating-decimal": 2, + "no-implicit-coercion": 0, + "no-invalid-this": 0, + "no-lone-blocks": 0, + "no-loop-func": 0, + "no-magic-numbers": 0, + "no-multi-spaces": 0, + "no-multi-str": 2, + "no-native-reassign": 2, + "no-new-func": 2, + "no-new-wrappers": 2, + "no-new": 2, + "no-octal-escape": 2, + "no-octal": 1, + "no-param-reassign": 0, + "no-process-env": 0, + "no-proto": 2, + "no-redeclare": 2, + "no-return-assign": [2, "except-parens"], + "no-self-compare": 2, + "no-sequences": 1, + "no-throw-literal": 2, + "no-unused-expressions": 2, + "no-useless-call": 2, + "no-useless-concat": 0, + "no-void": 0, + "no-warning-comments": 0, + "no-with": 2, + "radix": 1, + "vars-on-top": 0, + "wrap-iife": [2, "inside"], + "yoda": 0, + "strict": 0, + "init-declarations": 0, + "no-delete-var": 2, + "no-label-var": 2, + "no-shadow-restricted-names": 2, + "no-shadow": 0, + "no-undef-init": 0, + "no-undef": [2, {"typeof": true}], + "no-undefined": 0, + "no-unused-vars": [1, {"args": "none"}], + "no-use-before-define": [2, "nofunc"], + + "no-new-require": 2, + + "array-bracket-spacing": [2, "never"], + "block-spacing": 0, + "brace-style": [2, "1tbs", {"allowSingleLine": true}], + "camelcase": 0, + "comma-spacing": [2, {"before": false, "after": true}], + "comma-style": [2, "last"], + "computed-property-spacing": [2, "never"], + "consistent-this": 0, + "eol-last": os.EOL === '\n' ? [2, "unix"] : 0, + "func-names": 0, + "func-style": 0, + "id-length": 0, + "id-match": 0, + "indent": [2, "tab"], + "key-spacing": 0, + "linebreak-style": os.EOL === '\n' ? [2, "unix"] : 0, + "lines-around-comment": 0, + "max-nested-callbacks": 0, + "new-cap": 2, + "new-parens": 2, + "newline-after-var": 0, + "no-array-constructor": 2, + "no-continue": 0, + "no-inline-comments": 0, + "no-lonely-if": 0, + "no-mixed-spaces-and-tabs": [2, "smart-tabs"], + "no-multiple-empty-lines": [2, {"max": 2, "maxEOF": 1}], + "no-negated-condition": 0, + "no-nested-ternary": 0, + "no-new-object": 2, + "no-spaced-func": 2, + "no-ternary": 0, + "no-trailing-spaces": 2, + "no-underscore-dangle": 0, + "no-unneeded-ternary": 2, + "object-curly-spacing": [2, "never"], + "one-var": 0, + "operator-assignment": 0, + "operator-linebreak": [2, "after"], + "padded-blocks": [2, "never"], + "quote-props": 0, + "quotes": 0, + "require-jsdoc": 0, + "semi-spacing": [2, {"before": false, "after": true}], + "semi": [2, "always"], + "sort-vars": 0, + "space-after-keywords": [2, "always"], + "space-before-blocks": [2, "always"], + "space-before-function-paren": [2, {"anonymous": "always", "named": "never"}], + "space-before-keywords": [2, "always"], + "space-in-parens": [2, "never"], + "space-infix-ops": 2, + "space-return-throw-case": 2, + "space-unary-ops": [2, {"words": true, "nonwords": false}], + "spaced-comment": 0, + "wrap-regex": 0, + + "validate-conditionals": 2 + } +}; diff --git a/dev-tools/eslint/config-compat.js b/dev-tools/eslint/config-compat.js new file mode 100644 index 000000000000..0004d783f2e9 --- /dev/null +++ b/dev-tools/eslint/config-compat.js @@ -0,0 +1,10 @@ +module.exports = { + "extends": "./config-base.js", + "env": { + "browser": true, + "es6": false + }, + "rules": { + "quote-props": [2, "as-needed", {"keywords": true, "unnecessary": false}] + } +}; diff --git a/dev-tools/eslint/config-config.js b/dev-tools/eslint/config-config.js new file mode 100644 index 000000000000..5e62d63bc96a --- /dev/null +++ b/dev-tools/eslint/config-config.js @@ -0,0 +1,6 @@ +module.exports = { + "extends": "./config-base.js", + "rules": { + "comma-dangle": 0 + } +}; diff --git a/dev-tools/eslint/config-data-compact.js b/dev-tools/eslint/config-data-compact.js new file mode 100644 index 000000000000..cdc27e307c98 --- /dev/null +++ b/dev-tools/eslint/config-data-compact.js @@ -0,0 +1,7 @@ +module.exports = { + "extends": "./config-data.js", + "rules": { + "key-spacing": [2, {"beforeColon": false, "afterColon": false}], + "indent": 0, + } +}; diff --git a/dev-tools/eslint/config-data.js b/dev-tools/eslint/config-data.js new file mode 100644 index 000000000000..bc5d32bd9a96 --- /dev/null +++ b/dev-tools/eslint/config-data.js @@ -0,0 +1,17 @@ +module.exports = { + "extends": "./config-base.js", + "rules": { + "comma-dangle": [2, "never"], + "comma-spacing": [2, {"before": false, "after": false}], + "no-restricted-syntax": [2, + "ReturnStatement", "LabeledStatement", "BreakStatement", "ContinueStatement", + "IfStatement", "SwitchStatement", + "WhileStatement", "DoWhileStatement", "ForStatement", "ForInStatement", + "FunctionDeclaration", "VariableDeclaration", + "FunctionExpression", + "UpdateExpression", + "BinaryExpression", "LogicalExpression", + "ConditionalExpression", "CallExpression", "NewExpression", "SequenceExpression" + ] + } +}; diff --git a/dev-tools/eslint/config-test.js b/dev-tools/eslint/config-test.js new file mode 100644 index 000000000000..b79ce9c74bdc --- /dev/null +++ b/dev-tools/eslint/config-test.js @@ -0,0 +1,9 @@ +module.exports = { + "extends": "./config-base.js", + "env": { + "mocha": true + }, + "globals": { + "BattleEngine": false + }, +}; diff --git a/dev-tools/eslint/validate-conditionals.js b/dev-tools/eslint/validate-conditionals.js new file mode 100644 index 000000000000..35799dcbeeb8 --- /dev/null +++ b/dev-tools/eslint/validate-conditionals.js @@ -0,0 +1,87 @@ +/** + * Enforces Pokémon Showdown code style for conditionals + * + * Reliant on specific active settings for ESLint's rule "Require Following Curly Brace Conventions" (curly) + * curly: [2, "multi-line", "consistent"] + * + * ##### Valid + * + * ```js + * if (console.log) { + * console.log("Test"); + * } + * + * if (console.log) { + * console.log("Test"); + * } else { + * throw new Error("Error"); + * } + * + * if (console.log) { + * console.log("Test"); + * } else { + * 0; + * } + * + * if (console.log) { + * console.log("Test"); + * } else if (Number.isFinite) { + * Number.isFinite(42); + * } + * + * if (Math.random) Math.random(); + * + * if (a == 1) // Do something with this magic number + * ``` + * + * ##### Invalid + * + * ```js + * if (console.log) { + * console.log("Test"); + * } else if (Number.isFinite) Number.isFinite(); + * + * if (Math.random) { + * Math.random(); + * } else {Number.isFinite()}; + * + * if (Math.random) { + * Math.random(); + * } else if (Number.isFinite) {Number.isFinite()}; + * + * if (Math.random) Math.random(); + * else { + * Number.isFinite(); + * } + * + * if (Math.random) Math.random(); else Number.isFinite(); + * + * if (Math.random) Math.random(); + * else Number.isFinite(); + * + * if (Math.random) Math.random(); + * else if (Number.isFinite) Number.isFinite(); + * else Number.isInteger(); + * + * if (Math.random) + * Math.random(); + * + * ``` + */ + +module.exports = function (context) { + return { + "IfStatement": function (node) { + if (!node.alternate) return; + if (node.consequent.loc.end.line > node.consequent.loc.start.line) return; + if (node.consequent.loc.end.line >= node.alternate.loc.start.line - 1) { + context.report({ + node: node.alternate, + message: "Nested conditional must span across multiple lines." + }); + } + } + }; +}; + +module.exports.schema = []; diff --git a/dev-tools/jscs-custom-rules/validate-case-indentation.js b/dev-tools/jscs-custom-rules/validate-case-indentation.js deleted file mode 100644 index 9e3fa4a5b169..000000000000 --- a/dev-tools/jscs-custom-rules/validate-case-indentation.js +++ /dev/null @@ -1,80 +0,0 @@ -/** - * Enforces Pokémon Showdown code style for switch cases - * - * Type: `Boolean` - * - * Value: `true` - * - * #### Example - * - * ```js - * "validateCaseIndentation": true - * ``` - * - * ##### Valid - * - * ```js - * switch (foo) { - * case 'foo': - * // Do some stuff - * } - * - * switch (foo) { - * case 'foo': - * // Do some stuff - * default: - * // Do some other stuff - * } - * ``` - * - * ##### Invalid - * - * ```js - * switch (foo) { - * case 'foo': - * // Do some stuff - * } - * - * switch (foo) { - * case 'foo': - * // Do some stuff - * default: - * // Do some other stuff - * } - * ``` - */ - -'use strict'; - -const assert = require('assert'); - -module.exports = function () {}; - -module.exports.prototype = { - - configure: function (options) { - assert( - options === true, - this.getOptionName() + ' option requires a true value or should be removed' - ); - }, - - getOptionName: function () { - return 'validateCaseIndentation'; - }, - - check: function (file, errors) { - file.iterateNodesByType('SwitchStatement', function (node) { - let column = node.loc.start.column; - let currentLine = 0; - for (let i = 0; i < node.cases.length; i++) { - let currentCase = node.cases[i]; - if (currentCase.loc.line === currentLine) continue; - currentLine = currentCase.loc.line; - if (currentCase.loc.start.column === column) continue; - errors.add("Bad indentation for case", currentCase.loc.start); - break; - } - }); - } -}; diff --git a/dev-tools/jscs-custom-rules/validate-conditionals.js b/dev-tools/jscs-custom-rules/validate-conditionals.js deleted file mode 100644 index a5d208c12eeb..000000000000 --- a/dev-tools/jscs-custom-rules/validate-conditionals.js +++ /dev/null @@ -1,167 +0,0 @@ -/** - * Enforces Pokémon Showdown code style for conditionals - * - * Type: `Boolean` - * - * Value: `true` - * - * #### Example - * - * ```js - * "validateConditionals": true - * ``` - * - * ##### Valid - * - * ```js - * if (console.log) { - * console.log("Test"); - * } - * - * if (console.log) { - * console.log("Test"); - * } else { - * throw new Error("Error"); - * } - * - * if (console.log) { - * console.log("Test"); - * } else { - * 0; - * } - * - * if (console.log) { - * console.log("Test"); - * } else if (Number.isFinite) { - * Number.isFinite(42); - * } - * - * if (Math.random) Math.random(); - * - * if (a == 1) // Do something with this magic number - * ``` - * - * ##### Invalid - * - * ```js - * if (console.log) { - * console.log("Test"); - * } else if (Number.isFinite) Number.isFinite(); - * - * if (Math.random) { - * Math.random(); - * } else {Number.isFinite()}; - * - * if (Math.random) { - * Math.random(); - * } else if (Number.isFinite) {Number.isFinite()}; - * - * if (Math.random) Math.random(); - * else { - * Number.isFinite(); - * } - * - * if (Math.random) Math.random(); else Number.isFinite(); - * - * if (Math.random) Math.random(); - * else Number.isFinite(); - * - * if (Math.random) Math.random(); - * else if (Number.isFinite) Number.isFinite(); - * else Number.isInteger(); - * - * if (Math.random) - * Math.random(); - * - * ``` - */ - -'use strict'; - -const assert = require('assert'); - -module.exports = function () {}; - -module.exports.prototype = { - - configure: function (options) { - assert( - options === true, - this.getOptionName() + ' option requires a true value or should be removed' - ); - }, - - getOptionName: function () { - return 'validateConditionals'; - }, - - check: function (file, errors) { - file.iterateNodesByType('IfStatement', function (node) { - let consequent = node.consequent; - let statementType = consequent.type; - - // Either all `BlockStatement` or none. - let subNode = node; - while (subNode.alternate) { - subNode = subNode.alternate; - if (subNode.type === 'IfStatement') { - if (subNode.consequent.type !== statementType) { - errors.add("Mixed conditional blocks and expressions are disallowed", subNode.loc.start); - break; - } else if (subNode.consequent.type !== 'BlockStatement') { - errors.add("Nested conditionals require curly braces", subNode.loc.start); - break; - } - } else { - if (subNode.type !== statementType && (subNode.type === 'BlockStatement' || statementType === 'BlockStatement')) { - errors.add("Mixed conditional blocks and expressions are disallowed", subNode.loc.start); - } else if (subNode.type !== 'BlockStatement') { - errors.add("Nested conditionals require curly braces", subNode.loc.start); - } - break; - } - } - - // Curly braces iff multiline - let nodesCheck = [consequent]; - if (node.alternate) nodesCheck.push(node.alternate); - for (let i = 0; i < nodesCheck.length; i++) { - let subNode = nodesCheck[i]; - if (subNode.type === 'BlockStatement') { - let openingBrace = file.getFirstNodeToken(subNode); - let closingBrace = file.getLastNodeToken(subNode); - if (!subNode.body.length) { - // Empty block - errors.assert.differentLine({ - token: openingBrace, - nextToken: closingBrace - }); - continue; - } - let nextToken = file.getFirstNodeToken(subNode.body[0]); - let prevToken = file.getPrevToken(closingBrace); - - errors.assert.differentLine({ - token: openingBrace, - nextToken: nextToken, - message: 'Newline after opening curly brace required for block conditional (a)' - }); - errors.assert.differentLine({ - token: prevToken, - nextToken: closingBrace, - message: 'Newline before closing curly brace required for block conditional (b)' - }); - } else if (subNode.type !== 'IfStatement') { - if (subNode === consequent) { - let token = file.getFirstNodeToken(subNode); - errors.assert.sameLine({ - token: node.test, - nextToken: token, - message: 'Newline disallowed in non-block conditional (b)' - }); - } - } - } - }); - } -}; diff --git a/dnsbl.js b/dnsbl.js index 16753da6e469..d27ca7b99298 100644 --- a/dnsbl.js +++ b/dnsbl.js @@ -16,7 +16,6 @@ const BLOCKLISTS = ['sbl.spamhaus.org', 'rbl.efnetrbl.org']; let dns = require('dns'); -/* global Dnsbl: true */ let Dnsbl = module.exports; let dnsblCache = exports.cache = { diff --git a/gulpfile.js b/gulpfile.js deleted file mode 100644 index bc1d90f48f1f..000000000000 --- a/gulpfile.js +++ /dev/null @@ -1,225 +0,0 @@ -'use strict'; - -const path = require('path'); -const util = require('util'); - -const gulp = require('gulp'); -const lazypipe = require('lazypipe'); -const merge = require('merge-stream'); -const cache = require('gulp-cache'); -const jscs = require('gulp-jscs'); -const jshint = require('gulp-jshint'); -const replace = require('gulp-replace'); -const CacheSwap = require('cache-swap'); -const jshintStylish = require('jshint-stylish'); - -const fileCache = new CacheSwap({tmpDir: '', cacheDirName: 'gulp-cache'}); - -let globals = {}; -let globalList = [ - 'Config', 'Monitor', 'toId', 'Tools', 'LoginServer', 'Users', 'Rooms', 'Verifier', - 'CommandParser', 'Simulator', 'Tournaments', 'Dnsbl', 'Cidr', 'Sockets', 'TeamValidator', - 'Ladders' -]; -globalList.forEach(function (identifier) {globals[identifier] = false;}); - -function lint(jsHintOptions, jscsOptions) { - function cachedJsHint() { - return cache(jshint(jsHintOptions), { - success: function (file) { - return file.jshint.success; - }, - value: function (file) { - return {jshint: file.jshint}; - }, - fileCache: fileCache - }); - } - return lazypipe() - .pipe(cachedJsHint) - .pipe(jscs.bind(jscs, jscsOptions))(); -} - -let jsHintOptions = {}; -jsHintOptions.base = { - "nonbsp": true, - "nonew": true, - "noarg": true, - "loopfunc": true, - "latedef": 'nofunc', - - "freeze": true, - "undef": true, - - "sub": true, - "evil": true, - "esnext": true, - "node": true, - "eqeqeq": true, - - "globals": globals -}; -jsHintOptions.legacy = util._extend(util._extend({}, jsHintOptions.base), { - "es3": true -}); -jsHintOptions.test = util._extend(util._extend({}, jsHintOptions.base), { - "globals": util._extend(globals, { - "BattleEngine": false - }), - "mocha": true -}); - -let jscsOptions = {}; -jscsOptions.base = { - "preset": "yandex", - - "additionalRules": [ - new (require('./dev-tools/jscs-custom-rules/validate-conditionals.js'))(), - new (require('./dev-tools/jscs-custom-rules/validate-case-indentation.js'))() - ], - "validateConditionals": true, - "validateCaseIndentation": true, - - "requireCurlyBraces": null, - - "maximumLineLength": null, - "validateIndentation": '\t', - "validateQuoteMarks": null, - "disallowQuotedKeysInObjects": null, - "requireDotNotation": null, - - "disallowMultipleVarDecl": null, - "disallowImplicitTypeConversion": null, - "requireSpaceAfterLineComment": null, - - "disallowMixedSpacesAndTabs": "smart", - "requireSpaceAfterKeywords": true, - "requireSpaceAfterBinaryOperators": [ - '=', '+=', '-=', '*=', '/=', '%=', '<<=', '>>=', '>>>=', - '&=', '|=', '^=', - - '+', '-', '*', '/', '%', '<<', '>>', '>>>', '&', - '|', '^', '&&', '||', '===', '==', '>=', - '<=', '<', '>', '!=', '!==', - - ',' - ], - - "disallowSpacesInCallExpression": true, - "validateParameterSeparator": ", ", - - "requireBlocksOnNewline": 1, - "disallowPaddingNewlinesInBlocks": true, - - "disallowSpaceBeforeSemicolon": true, - "requireOperatorBeforeLineBreak": true, - "disallowTrailingComma": true, - - "requireCapitalizedConstructors": true, - - "validateLineBreaks": require('os').EOL === '\n' ? 'LF' : null, - "disallowMultipleLineBreaks": null -}; -jscsOptions.config = util._extend(util._extend({}, jscsOptions.base), { - "disallowTrailingComma": null -}); -jscsOptions.dataCompactArr = util._extend(util._extend({}, jscsOptions.base), { - "requireSpaceAfterBinaryOperators": ["="], - "requireSpaceBeforeBinaryOperators": ["="], - "disallowSpaceAfterBinaryOperators": [","], - "disallowSpaceBeforeBinaryOperators": [","] -}); -jscsOptions.dataCompactAll = { - "disallowTrailingComma": true, - - "validateLineBreaks": 'CI' in process.env ? 'LF' : null, - "requireLineFeedAtFileEnd": true, - "requireSpaceAfterBinaryOperators": ["="], - "requireSpaceBeforeBinaryOperators": ["="], - - "validateQuoteMarks": "\"", - "disallowQuotedKeysInObjects": "allButReserved", - - "disallowSpaceAfterObjectKeys": true, - "disallowSpaceBeforeObjectValues": true, - "disallowSpacesInsideBrackets": true, - "disallowSpacesInsideArrayBrackets": true, - "disallowSpacesInsideObjectBrackets": true, - "disallowSpacesInsideParentheses": true, - "disallowSpaceAfterBinaryOperators": [","], - "disallowSpaceBeforeBinaryOperators": [","] -}; -jscsOptions.dataCompactAllIndented = util._extend(util._extend({}, jscsOptions.dataCompactAll), { - "validateIndentation": '\t' -}); - -let lintData = [ - { - dirs: ['./*.js', './tournaments/*.js', './chat-plugins/*.js', './config/!(config).js', './data/rulesets.js', './data/statuses.js'], - jsHint: jsHintOptions.base, - jscs: jscsOptions.base - }, { - dirs: ['./data/scripts.js', './mods/*/scripts.js', './mods/*/rulesets.js', './mods/*/statuses.js', './dev-tools/**.js'], - jsHint: jsHintOptions.base, - jscs: jscsOptions.base - }, { - dirs: ['./config/config*.js'], - jsHint: jsHintOptions.base, - jscs: jscsOptions.config - }, { - dirs: ['./data/abilities.js', './data/items.js', './data/moves.js', './data/typechart.js', './data/aliases.js', './mods/*/abilities.js', './mods/*/items.js', './mods/*/moves.js', './mods/*/typechart.js'], - jsHint: jsHintOptions.legacy, - jscs: jscsOptions.base - }, { - dirs: ['./data/formats-data.js', './mods/*/formats-data.js', './mods/!(gen1)/pokedex.js'], - jsHint: jsHintOptions.legacy, - jscs: jscsOptions.dataCompactArr - }, { - dirs: ['./data/pokedex.js', './mods/gen1/pokedex.js'], - jsHint: jsHintOptions.legacy, - jscs: jscsOptions.dataCompactAll - }, { - dirs: ['./test/*.js', './test/application/*.js', './test/simulator/*/*.js', './test/dev-tools/*/*.js'], - jsHint: jsHintOptions.test, - jscs: jscsOptions.base - } -]; -lintData.extra = { - fastlint: lintData[0], - learnsets: { - dirs: ['./data/learnsets*.js', './mods/*/learnsets.js'], - jsHint: jsHintOptions.legacy, - jscs: jscsOptions.dataCompactAllIndented - } -}; - -let linter = function () { - return ( - merge.apply( - null, - lintData.map(function (source) { - return gulp.src(source.dirs) - .pipe(lint(source.jsHint, source.jscs)); - }) - ).pipe(jshint.reporter(jshintStylish)) - .pipe(jshint.reporter('fail')) - ); -}; - -for (let taskName in lintData.extra) { - gulp.task(taskName, (function (task) { - return function () { - return gulp.src(task.dirs) - .pipe(lint(task.jsHint, task.jscs)) - .pipe(jshint.reporter(jshintStylish)) - .pipe(jshint.reporter('fail')); - }; - })(lintData.extra[taskName])); -} - -gulp.task('clear', function (done) { - fileCache.clear('default', done); -}); - -gulp.task('lint', linter); -gulp.task('default', linter); diff --git a/ladders-remote.js b/ladders-remote.js index 7cfadd9a8d2e..6dbd366818eb 100644 --- a/ladders-remote.js +++ b/ladders-remote.js @@ -7,7 +7,6 @@ * @license MIT license */ -/* global Ladders: true */ let Ladders = Ladders.get = module.exports = getLadder; function getLadder(formatid) { diff --git a/ladders.js b/ladders.js index ef9fdee6230d..5ef342c9e896 100644 --- a/ladders.js +++ b/ladders.js @@ -7,8 +7,6 @@ * @license MIT license */ -/* global Ladders: true */ - 'use strict'; let Ladders = module.exports = getLadder; diff --git a/loginserver.js b/loginserver.js index 268e1362fc0d..868c5b71ec16 100644 --- a/loginserver.js +++ b/loginserver.js @@ -15,7 +15,6 @@ const LOGIN_SERVER_BATCH_TIME = 1000; const http = require("http"); const url = require('url'); -/* global LoginServer: true */ let LoginServer = module.exports = (function () { function LoginServer(uri) { console.log('Creating LoginServer object for ' + uri + '...'); diff --git a/mods/stadium/scripts.js b/mods/stadium/scripts.js index dbfd5a4aae56..db4aaecc47af 100644 --- a/mods/stadium/scripts.js +++ b/mods/stadium/scripts.js @@ -258,7 +258,7 @@ exports.BattleScripts = { // We get the sub to the target to see if it existed let targetSub = (target) ? target.volatiles['substitute'] : false; - let targetHadSub = (targetSub !== null && targetSub !== false && (typeof targetSub !== 'undefined')); + let targetHadSub = (targetSub !== null && targetSub !== false && (typeof targetSub !== 'undefined')); // eslint-disable-line no-unused-vars if (target) { hitResult = this.singleEvent('TryHit', moveData, {}, target, pokemon, move); diff --git a/monitor.js b/monitor.js index 1f9e55748561..388cae30f2dc 100644 --- a/monitor.js +++ b/monitor.js @@ -11,8 +11,7 @@ const fs = require('fs'); const path = require('path'); -/* global Monitor: true */ -const Monitor = module.exports = { +const Monitor = module.exports = { // eslint-disable-line no-unused-vars /********************************************************* * Logging diff --git a/package.json b/package.json index 4de6e5813440..7e7fe2ffb03c 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "main": "app.js", "scripts": { "start": "node app.js", - "test": "gulp && mocha" + "test": "eslint --config dev-tools/eslint/config-base.js --rulesdir dev-tools/eslint --cache --cache-file=eslint-cache/base *.js config/formats.js chat-plugins/*.js tournaments/*.js data/rulesets.js data/scripts.js data/statuses.js mods/**/abilities.js mods/**/items.js mods/**/moves.js mods/**/rulesets.js mods/**/scripts.js mods/**/statuses.js && eslint --config dev-tools/eslint/config-config.js --rulesdir dev-tools/eslint --cache --cache-file=eslint-cache/config config/config*.js && eslint --config dev-tools/eslint/config-compat.js --rulesdir dev-tools/eslint --cache --cache-file=eslint-cache/compat data/abilities.js data/items.js data/moves.js data/typechart.js data/aliases.js mods/*/abilities.js mods/*/items.js mods/*/moves.js mods/*/typechart.js && eslint --config dev-tools/eslint/config-data.js --rulesdir dev-tools/eslint --cache --cache-file=eslint-cache/data data/formats-data.js mods/*/formats-data.js mods/gen4/pokedex.js mods/gen5/pokedex.js && eslint --config dev-tools/eslint/config-data-compact.js --rulesdir dev-tools/eslint --cache --cache-file=eslint-cache/data-compact data/pokedex.js mods/gen1/pokedex.js && eslint --config dev-tools/eslint/config-test.js --rulesdir dev-tools/eslint --cache --cache-file=eslint-cache/test test/*.js test/application/*.js test/simulator/*/*.js test/dev-tools/*/*.js && mocha" }, "bin": "./app.js", "homepage": "http://play.pokemonshowdown.com", @@ -49,16 +49,7 @@ "private": true, "license": "MIT", "devDependencies": { - "cache-swap": "~0.2.1", - "gulp": "~3.9.0", - "gulp-cache": "~0.3.0", - "gulp-jshint": "~1.11.2", - "gulp-jscs": "~2.0.0", - "gulp-replace": "~0.5.3", - "jshint-stylish": "~2.0.1", - "mocha": "~2.3.2", - "lazypipe": "~1.0.1", - "merge-stream": "~1.0.0", - "jscs": "~2.1.1" + "eslint": "~1.9.0", + "mocha": "~2.3.2" } } diff --git a/rooms.js b/rooms.js index 90c91c4e97b1..89cec0a5739d 100644 --- a/rooms.js +++ b/rooms.js @@ -18,7 +18,6 @@ const PERIODIC_MATCH_INTERVAL = 60 * 1000; const fs = require('fs'); -/* global Rooms: true */ let Rooms = module.exports = getRoom; let rooms = Rooms.rooms = Object.create(null); @@ -994,7 +993,7 @@ let BattleRoom = (function () { // empty rooms time out after ten minutes let hasUsers = false; - for (let i in this.users) { + for (let i in this.users) { // eslint-disable-line no-unused-vars hasUsers = true; break; } diff --git a/sockets.js b/sockets.js index 489a0beb7eb5..a7c6404f67c2 100644 --- a/sockets.js +++ b/sockets.js @@ -81,7 +81,7 @@ if (cluster.isMaster) { return count; }; - let killPid = exports.killPid = function (pid) { + let killPid = exports.killPid = function (pid) { // eslint-disable-line no-unused-vars pid = '' + pid; for (let id in workers) { let worker = workers[id]; @@ -240,7 +240,7 @@ if (cluster.isMaster) { } } }; - let interval = setInterval(sweepClosedSockets, 1000 * 60 * 10); + let interval = setInterval(sweepClosedSockets, 1000 * 60 * 10); // eslint-disable-line no-unused-vars process.on('message', function (data) { // console.log('worker received: ' + data); @@ -314,7 +314,7 @@ if (cluster.isMaster) { delete channel[socketid]; if (subchannels[channelid]) delete subchannels[channelid][socketid]; let isEmpty = true; - for (let socketid in channel) { + for (let socketid in channel) { // eslint-disable-line no-unused-vars isEmpty = false; break; } diff --git a/test/dev-tools/eslint/validate-conditionals.js b/test/dev-tools/eslint/validate-conditionals.js new file mode 100644 index 000000000000..4e6d42b73a3d --- /dev/null +++ b/test/dev-tools/eslint/validate-conditionals.js @@ -0,0 +1,29 @@ +"use strict"; + +describe("eslint-rules/validate-conditionals", function () { + var rule = require('./../../../dev-tools/eslint/validate-conditionals.js'); + var RuleTester = require('eslint/lib/testers/rule-tester'); + + var ruleTester = new RuleTester(); + ruleTester.run("validate-conditionals", rule, { + valid: [ + 'if (Math.random) {\nMath.random();\n}', + 'if (Math.random) {\n//This is a comment\n}', + 'if (Math.random) {\nMath.random();\n} else {\n0;\n}', + 'if (Math.random) Math.random();' + ], + invalid: [{ + code: 'if (Math.random) Math.random(); else Number.isFinite();', + errors: [{message: "Nested conditional must span across multiple lines."}] + }, { + code: 'if (Math.random) Math.random();\nelse Number.isFinite();', + errors: [{message: "Nested conditional must span across multiple lines."}] + }, { + code: 'if (Math.random) Math.random();\nelse if (Number.isFinite) Number.isFinite();\nelse Number.isInteger();', + errors: [{message: "Nested conditional must span across multiple lines."}, {message: "Nested conditional must span across multiple lines."}] + }, { + code: 'if (Math.random) Math.random();\nelse if (Number.isFinite) Number.isFinite();\nelse if (Number.isInteger) Number.isInteger();\nelse Number.parseInt();', + errors: [{message: "Nested conditional must span across multiple lines."}, {message: "Nested conditional must span across multiple lines."}, {message: "Nested conditional must span across multiple lines."}] + }] + }); +}); diff --git a/test/dev-tools/jscs-custom-rules/validate-case-indentation.js b/test/dev-tools/jscs-custom-rules/validate-case-indentation.js deleted file mode 100644 index cfd7a8bf4dd5..000000000000 --- a/test/dev-tools/jscs-custom-rules/validate-case-indentation.js +++ /dev/null @@ -1,48 +0,0 @@ -'use strict'; - -const Checker = require('jscs'); -const assert = require('assert'); - -describe('rules/validate-case-indentation', function () { - let checker; - - before(function () { - checker = new Checker(); - checker.configure({ - additionalRules: [new (require('./../../../dev-tools/jscs-custom-rules/validate-case-indentation.js'))()], - validateCaseIndentation: true - }); - }); - - describe('option value true', function () { - it('should report cases not aligned with switch keyword', function () { - let src = 'switch (Number.isFinite) {\n'; - src += '\tcase isFinite:\n'; - src += '\t\tbreak;\n'; - src += '}'; - assert(!checker.checkString(src).isEmpty()); - }); - - it('should not report cases aligned with switch keyword', function () { - let src = 'switch (Number.isFinite) {\n'; - src += 'case isFinite:\n'; - src += '\tbreak;\n'; - src += '}'; - assert(checker.checkString(src).isEmpty()); - }); - - it('should report default case not aligned with switch keyword', function () { - let src = 'switch (Number.isFinite) {\n'; - src += '\tdefault:\n'; - src += '}'; - assert(!checker.checkString(src).isEmpty()); - }); - - it('should not report default case aligned with switch keyword', function () { - let src = 'switch (Number.isFinite) {\n'; - src += 'default:\n'; - src += '}'; - assert(checker.checkString(src).isEmpty()); - }); - }); -}); diff --git a/test/dev-tools/jscs-custom-rules/validate-conditionals.js b/test/dev-tools/jscs-custom-rules/validate-conditionals.js deleted file mode 100644 index b71cdc90d9ad..000000000000 --- a/test/dev-tools/jscs-custom-rules/validate-conditionals.js +++ /dev/null @@ -1,82 +0,0 @@ -'use strict'; - -const Checker = require('jscs'); -const assert = require('assert'); - -describe('rules/validate-conditionals', function () { - let checker; - - before(function () { - checker = new Checker(); - checker.configure({ - additionalRules: [new (require('./../../../dev-tools/jscs-custom-rules/validate-conditionals.js'))()], - validateConditionals: true - }); - }); - - describe('option value true', function () { - it('should report braces if only in consequent', function () { - assert(!checker.checkString('if (Math.random) {\nMath.random();\n} else 0;').isEmpty()); - }); - - it('should report braces if only in alternate without indentation', function () { - assert(!checker.checkString('if (Math.random) Math.random();\nelse {\n0;\n}').isEmpty()); - }); - - it('should report braces if only in alternate with indentation', function () { - assert(!checker.checkString('if (Math.random) Math.random();\nelse {\n\t0;\n}').isEmpty()); - }); - - it('should report lack of braces for multiline consequent', function () { - assert(!checker.checkString('if (Math.random)\nMath.random();').isEmpty()); - }); - - it('should report lack of braces for multiline alternate', function () { - assert(!checker.checkString('if (Math.random) {\nMath.random()\n} else\n0;').isEmpty()); - }); - - it('should report braces for single-line consequent', function () { - assert(!checker.checkString('if (Math.random) {Math.random();}').isEmpty()); - }); - - it('should report braces for single-line alternate', function () { - assert(!checker.checkString('if (Math.random) {\nMath.random();\n} else {0;}').isEmpty()); - }); - - it('should report lack of braces for single-line alternate', function () { - assert(!checker.checkString('if (Math.random) Math.random();\nelse Number.isFinite();').isEmpty()); - }); - - it('should report lack of braces for nested conditionals', function () { - assert(!checker.checkString('if (Math.random) Math.random();\nelse if (Number.isFinite) Number.isFinite();\nelse Number.isInteger();').isEmpty()); - }); - - it('should report lack of braces for nested conditionals', function () { - assert(!checker.checkString('if (Math.random) Math.random();\nelse if (Number.isFinite) Number.isFinite();\nelse if (Number.isInteger) Number.isInteger();\nelse Number.parseInt();').isEmpty()); - }); - - it('should report single-line if-else', function () { - assert(!checker.checkString('if (Math.random) Math.random(); else Number.isFinite();').isEmpty()); - }); - - it('should not report braces for multiline consequent', function () { - assert(checker.checkString('if (Math.random) {\nMath.random();\n}').isEmpty()); - }); - - it('should report single-line empty blocks', function () { - assert(!checker.checkString('if (Math.random) {}').isEmpty()); - }); - - it('should not report braces for empty blocks', function () { - assert(checker.checkString('if (Math.random) {\n//This is a comment\n}').isEmpty()); - }); - - it('should not report braces for multiline alternate', function () { - assert(checker.checkString('if (Math.random) {\nMath.random();\n} else {\n0;\n}').isEmpty()); - }); - - it('should not report lack of braces for single-line conditional', function () { - assert(checker.checkString('if (Math.random) Math.random();').isEmpty()); - }); - }); -}); diff --git a/users.js b/users.js index 36255b152e95..61ed248ab2ba 100644 --- a/users.js +++ b/users.js @@ -31,7 +31,6 @@ const THROTTLE_MULTILINE_WARN = 4; const fs = require('fs'); -/* global Users: true */ let Users = module.exports = getUser; let User, Connection;