Repository: eslint/eslint
Pull request #10184 (2018-04-04 16:21:45)

Upgrade: upgrade deps
<!--
    ESLint adheres to the [JS Foundation Code of Conduct](https://js.foundation/community/code-of-conduct).
-->

**What is the purpose of this pull request? (put an "X" next to item)**

[ ] Documentation update
[ ] Bug fix ([template](https://raw.githubusercontent.com/eslint/eslint/master/templates/bug-report.md))
[ ] New rule ([template](https://raw.githubusercontent.com/eslint/eslint/master/templates/rule-proposal.md))
[ ] Changes an existing rule ([template](https://raw.githubusercontent.com/eslint/eslint/master/templates/rule-change-proposal.md))
[ ] Add autofixing to a rule
[ ] Add a CLI option
[ ] Add something to the core
[X] Other, please explain:
Upgrade some deps.

<!--
    If the item you've checked above has a template, please paste the template questions below and answer them. (If this pull request is addressing an issue, you can just paste a link to the issue here instead.)
-->

<!--
    Please ensure your pull request is ready:

    - Read the pull request guide (https://eslint.org/docs/developer-guide/contributing/pull-requests)
    - Include tests for this change
    - Update documentation for this change (if appropriate)
-->

<!--
    The following is required for all pull requests:
-->

**What changes did you make? (Give an overview)**
Upgrade major versions of cross-spawn and inquirer.

**Is there anything you'd like reviewers to focus on?**
No.



not-an-aardvark: I think the latest version of `inquirer` has dropped support for Node 4, which we still support on master since https://github.com/eslint/eslint/pull/10074 hasn't been merged yet.

Patch:
diff --git a/.travis.yml b/.travis.yml
index d481188d3..5763f04af 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,9 +1,6 @@
 language: node_js
 node_js:
-    - "4"
-    - "5"
     - "6"
-    - "7"
     - "8"
     - "9"
 sudo: false
diff --git a/Makefile.js b/Makefile.js
index 63b6204fa..78063832f 100644
--- a/Makefile.js
+++ b/Makefile.js
@@ -979,10 +979,7 @@ function createConfigForPerformanceTest() {
         "rules:"
     ];
 
-    content.push.apply(
-        content,
-        ls("lib/rules").map(fileName => `    ${path.basename(fileName, ".js")}: 1`)
-    );
+    content.push(...ls("lib/rules").map(fileName => `    ${path.basename(fileName, ".js")}: 1`));
 
     content.join("\n").to(PERF_ESLINTRC);
 }
diff --git a/README.md b/README.md
index ccf0cda62..ed991e14f 100644
--- a/README.md
+++ b/README.md
@@ -27,7 +27,7 @@ ESLint is a tool for identifying and reporting on patterns found in ECMAScript/J
 
 ## Installation and Usage
 
-Prerequisites: [Node.js](https://nodejs.org/en/) (>=4.x), npm version 2+.
+Prerequisites: [Node.js](https://nodejs.org/en/) (>=6.14), npm version 3+.
 
 There are two ways to install ESLint: globally and locally.
 
diff --git a/docs/developer-guide/shareable-configs.md b/docs/developer-guide/shareable-configs.md
index cecc74589..41d8b8f35 100644
--- a/docs/developer-guide/shareable-configs.md
+++ b/docs/developer-guide/shareable-configs.md
@@ -110,7 +110,7 @@ As an example, you can create a file called `my-special-config.js` in the root o
 ```js
 module.exports = {
     rules: {
-        quotes: [2, "double"];
+        quotes: [2, "double"]
     }
 };
 ```
diff --git a/docs/developer-guide/working-with-rules.md b/docs/developer-guide/working-with-rules.md
index dedfccc86..7acb318b4 100644
--- a/docs/developer-guide/working-with-rules.md
+++ b/docs/developer-guide/working-with-rules.md
@@ -427,7 +427,7 @@ module.exports = {
                 },
                 "additionalProperties": false
             }
-        ];
+        ]
     },
 };
 ```
diff --git a/docs/rules/id-length.md b/docs/rules/id-length.md
index a28407fec..d49435d0b 100644
--- a/docs/rules/id-length.md
+++ b/docs/rules/id-length.md
@@ -34,7 +34,7 @@ function foo(...x) { }
 var { x } = {};
 var { x: a} = {};
 var { a: [x]} = {};
-({ prop: obj.x }) = {};
+({ prop: obj.x } = {});
 ```
 
 Examples of **correct** code for this rule with the default options:
@@ -62,7 +62,7 @@ function foo(...args) { }
 var { prop } = {};
 var { prop: a } = {};
 var { prop: [x] } = {};
-({ prop: obj.longName }) = {};
+({ prop: obj.longName } = {});
 var data = { "x": 1 };  // excused because of quotes
 data["y"] = 3;  // excused because of calculated property access
 ```
@@ -72,12 +72,12 @@ This rule has a shorthand integer option for the `"min"` object property.
 Examples of **incorrect** code for this rule with a minimum of 4:
 
 ```js
-/*eslint id-length: ["error", 4]*/
+/*eslint id-length: ["error", { "min": 4 }]*/
 /*eslint-env es6*/
 
 var val = 5;
 obj.e = document.body;
-function (e) { };
+function foo (e) { };
 try {
     dangerousStuff();
 } catch (e) {
@@ -91,13 +91,13 @@ function foo(...x) { }
 var { x } = {};
 var { x: a} = {};
 var { a: [x]} = {};
-({ prop: obj.x }) = {};
+({ prop: obj.x } = {});
 ```
 
 Examples of **correct** code for this rule with a minimum of 4:
 
 ```js
-/*eslint id-length: ["error", 4]*/
+/*eslint id-length: ["error", { "min": 4 }]*/
 /*eslint-env es6*/
 
 var value = 5;
@@ -118,7 +118,7 @@ function foobar(...args) { }
 var { prop } = {};
 var { prop: a } = {};
 var { prop: [x] } = {};
-({ prop: obj.name }) = {};
+({ prop: obj.name } = {});
 var data = { "x": 1 };  // excused because of quotes
 data["y"] = 3;  // excused because of calculated property access
 ```
@@ -141,7 +141,7 @@ Examples of **incorrect** code for this rule with the `{ "min": 4 }` option:
 
 var val = 5;
 obj.e = document.body;
-function (e) { };
+function foo (e) { };
 try {
     dangerousStuff();
 } catch (e) {
@@ -155,7 +155,7 @@ function foo(...x) { }
 var { x } = {};
 var { x: a} = {};
 var { a: [x]} = {};
-({ prop: obj.x }) = {};
+({ prop: obj.x } = {});
 ```
 
 Examples of **correct** code for this rule with the `{ "min": 4 }` option:
@@ -182,7 +182,7 @@ function foobar(...args) { }
 var { prop } = {};
 var { prop: a } = {};
 var { prop: [x] } = {};
-({ prop: obj.name }) = {};
+({ prop: obj.name } = {});
 var data = { "x": 1 };  // excused because of quotes
 data["y"] = 3;  // excused because of calculated property access
 ```
@@ -234,8 +234,8 @@ Examples of **correct** code for this rule with the `{ "properties": "never" }`
 /*eslint-env es6*/
 
 var myObj = { a: 1 };
-({ a: obj.x.y.z }) = {};
-({ prop: obj.i }) = {};
+({ a: obj.x.y.z } = {});
+({ prop: obj.i } = {});
 ```
 
 ### exceptions
diff --git a/docs/rules/max-statements-per-line.md b/docs/rules/max-statements-per-line.md
index 8b9be85b4..d7f51ec53 100644
--- a/docs/rules/max-statements-per-line.md
+++ b/docs/rules/max-statements-per-line.md
@@ -3,7 +3,7 @@
 A line of code containing too many statements can be difficult to read. Code is generally read from the top down, especially when scanning, so limiting the number of statements allowed on a single line can be very beneficial for readability and maintainability.
 
 ```js
-function () { var bar; if (condition) { bar = 1; } else { bar = 2; } return true; } // too many statements
+function foo () { var bar; if (condition) { bar = 1; } else { bar = 2; } return true; } // too many statements
 ```
 
 ## Rule Details
diff --git a/docs/rules/no-unused-vars.md b/docs/rules/no-unused-vars.md
index d7502ed5c..996dea181 100644
--- a/docs/rules/no-unused-vars.md
+++ b/docs/rules/no-unused-vars.md
@@ -150,7 +150,7 @@ console.log(secondVar);
 
 The `args` option has three settings:
 
-* `after-used` - only the last argument must be used. This allows you, for instance, to have two named parameters to a function and as long as you use the second argument, ESLint will not warn you about the first. This is the default setting.
+* `after-used` - unused positional arguments that occur before the last used argument will not be checked, but all named arguments and all positional arguments after the last used argument will be checked.
 * `all` - all named arguments must be used.
 * `none` - do not check arguments.
 
@@ -161,9 +161,10 @@ Examples of **incorrect** code for the default `{ "args": "after-used" }` option
 ```js
 /*eslint no-unused-vars: ["error", { "args": "after-used" }]*/
 
-// 1 error
+// 2 errors, for the parameters after the last used parameter (bar)
 // "baz" is defined but never used
-(function(foo, bar, baz) {
+// "qux" is defined but never used
+(function(foo, bar, baz, qux) {
     return bar;
 })();
 ```
@@ -173,8 +174,8 @@ Examples of **correct** code for the default `{ "args": "after-used" }` option:
 ```js
 /*eslint no-unused-vars: ["error", {"args": "after-used"}]*/
 
-(function(foo, bar, baz) {
-    return baz;
+(function(foo, bar, baz, qux) {
+    return qux;
 })();
 ```
 
diff --git a/docs/rules/operator-linebreak.md b/docs/rules/operator-linebreak.md
index 3b4b2f19d..e2a69a1fd 100644
--- a/docs/rules/operator-linebreak.md
+++ b/docs/rules/operator-linebreak.md
@@ -180,8 +180,9 @@ Examples of additional **correct** code for this rule with the `{ "overrides": {
 ```js
 /*eslint operator-linebreak: ["error", "after", { "overrides": { "+=": "before" } }]*/
 
-var thing
-  += 'thing';
+var thing = 'thing';
+thing
+  += 's';
 ```
 
 Examples of additional **correct** code for this rule with the `{ "overrides": { "?": "ignore", ":": "ignore" } }` option:
diff --git a/docs/user-guide/getting-started.md b/docs/user-guide/getting-started.md
index 22dcd497f..4b98eb075 100644
--- a/docs/user-guide/getting-started.md
+++ b/docs/user-guide/getting-started.md
@@ -13,7 +13,7 @@ ESLint is a tool for identifying and reporting on patterns found in ECMAScript/J
 
 ## Installation and Usage
 
-Prerequisites: [Node.js](https://nodejs.org/en/) (>=4.x), npm version 2+.
+Prerequisites: [Node.js](https://nodejs.org/en/) (>=6.14), npm version 3+.
 
 There are two ways to install ESLint: globally and locally.
 
diff --git a/lib/file-finder.js b/lib/file-finder.js
index 11091a99d..5d4b48a62 100644
--- a/lib/file-finder.js
+++ b/lib/file-finder.js
@@ -134,7 +134,7 @@ class FileFinder {
 
         // Add what has been cached previously to the cache of each directory searched.
         for (let i = 0; i < searched; i++) {
-            [].push.apply(cache[dirs[i]], cache[directory]);
+            cache[dirs[i]].push(...cache[directory]);
         }
 
         yield* cache[dirs[0]];
diff --git a/lib/linter.js b/lib/linter.js
index 2d46b4bd8..695e701c1 100644
--- a/lib/linter.js
+++ b/lib/linter.js
@@ -284,7 +284,7 @@ function getDirectiveComments(filename, ast, ruleMapper) {
         if (/^eslint-disable-(next-)?line$/.test(match[1]) && comment.loc.start.line === comment.loc.end.line) {
             const directiveType = match[1].slice("eslint-".length);
 
-            [].push.apply(disableDirectives, createDisableDirectives(directiveType, comment.loc.start, directiveValue));
+            disableDirectives.push(...createDisableDirectives(directiveType, comment.loc.start, directiveValue));
         } else if (comment.type === "Block") {
             switch (match[1]) {
                 case "exported":
@@ -297,11 +297,11 @@ function getDirectiveComments(filename, ast, ruleMapper) {
                     break;
 
                 case "eslint-disable":
-                    [].push.apply(disableDirectives, createDisableDirectives("disable", comment.loc.start, directiveValue));
+                    disableDirectives.push(...createDisableDirectives("disable", comment.loc.start, directiveValue));
                     break;
 
                 case "eslint-enable":
-                    [].push.apply(disableDirectives, createDisableDirectives("enable", comment.loc.start, directiveValue));
+                    disableDirectives.push(...createDisableDirectives("enable", comment.loc.start, directiveValue));
                     break;
 
                 case "eslint": {
@@ -724,10 +724,8 @@ const BASE_TRAVERSAL_CONTEXT = Object.freeze(
     Object.keys(DEPRECATED_SOURCECODE_PASSTHROUGHS).reduce(
         (contextInfo, methodName) =>
             Object.assign(contextInfo, {
-                [methodName]() {
-                    const sourceCode = this.getSourceCode();
-
-                    return sourceCode[DEPRECATED_SOURCECODE_PASSTHROUGHS[methodName]].apply(sourceCode, arguments);
+                [methodName](...args) {
+                    return this.getSourceCode()[DEPRECATED_SOURCECODE_PASSTHROUGHS[methodName]](...args);
                 }
             }),
         {}
@@ -816,7 +814,7 @@ function runRules(sourceCode, configuredRules, ruleMapper, parserOptions, parser
                 {
                     id: ruleId,
                     options: getRuleOptions(configuredRules[ruleId]),
-                    report() {
+                    report(...args) {
 
                         /*
                          * Create a report translator lazily.
@@ -831,7 +829,7 @@ function runRules(sourceCode, configuredRules, ruleMapper, parserOptions, parser
                         if (reportTranslator === null) {
                             reportTranslator = createReportTranslator({ ruleId, severity, sourceCode, messageIds });
                         }
-                        const problem = reportTranslator.apply(null, arguments);
+                        const problem = reportTranslator(...args);
 
                         if (problem.fix && rule.meta && !rule.meta.fixable) {
                             throw new Error("Fixable rules should export a `meta.fixable` property.");
diff --git a/lib/logging.js b/lib/logging.js
index 22451e535..3eb898c34 100644
--- a/lib/logging.js
+++ b/lib/logging.js
@@ -14,15 +14,15 @@ module.exports = {
      * Cover for console.log
      * @returns {void}
      */
-    info() {
-        console.log.apply(console, arguments);
+    info(...args) {
+        console.log(...args);
     },
 
     /**
      * Cover for console.error
      * @returns {void}
      */
-    error() {
-        console.error.apply(console, arguments);
+    error(...args) {
+        console.error(...args);
     }
 };
diff --git a/lib/report-translator.js b/lib/report-translator.js
index 17d410d2a..f82830586 100644
--- a/lib/report-translator.js
+++ b/lib/report-translator.js
@@ -51,35 +51,35 @@ const interpolate = require("./util/interpolate");
 
 /**
  * Translates a multi-argument context.report() call into a single object argument call
- * @param {...*} arguments A list of arguments passed to `context.report`
+ * @param {...*} args A list of arguments passed to `context.report`
  * @returns {MessageDescriptor} A normalized object containing report information
  */
-function normalizeMultiArgReportCall() {
+function normalizeMultiArgReportCall(...args) {
 
     // If there is one argument, it is considered to be a new-style call already.
-    if (arguments.length === 1) {
+    if (args.length === 1) {
 
         // Shallow clone the object to avoid surprises if reusing the descriptor
-        return Object.assign({}, arguments[0]);
+        return Object.assign({}, args[0]);
     }
 
     // If the second argument is a string, the arguments are interpreted as [node, message, data, fix].
-    if (typeof arguments[1] === "string") {
+    if (typeof args[1] === "string") {
         return {
-            node: arguments[0],
-            message: arguments[1],
-            data: arguments[2],
-            fix: arguments[3]
+            node: args[0],
+            message: args[1],
+            data: args[2],
+            fix: args[3]
         };
     }
 
     // Otherwise, the arguments are interpreted as [node, loc, message, data, fix].
     return {
-        node: arguments[0],
-        loc: arguments[1],
-        message: arguments[2],
-        data: arguments[3],
-        fix: arguments[4]
+        node: args[0],
+        loc: args[1],
+        message: args[2],
+        data: args[3],
+        fix: args[4]
     };
 }
 
@@ -240,8 +240,8 @@ module.exports = function createReportTranslator(metadata) {
      * called every time a rule reports a problem, which happens much less frequently (usually, the vast
      * majority of rules don't report any problems for a given file).
      */
-    return function() {
-        const descriptor = normalizeMultiArgReportCall.apply(null, arguments);
+    return (...args) => {
+        const descriptor = normalizeMultiArgReportCall(...args);
 
         assertValidNodeInfo(descriptor);
 
diff --git a/lib/rules/no-irregular-whitespace.js b/lib/rules/no-irregular-whitespace.js
index f1840aaf2..7f9adc10a 100644
--- a/lib/rules/no-irregular-whitespace.js
+++ b/lib/rules/no-irregular-whitespace.js
@@ -225,7 +225,7 @@ module.exports = {
 
                 // If we have any errors remaining report on them
                 errors.forEach(error => {
-                    context.report.apply(context, error);
+                    context.report(...error);
                 });
             };
         } else {
diff --git a/lib/rules/no-return-await.js b/lib/rules/no-return-await.js
index 490ccaeb3..fc3373d3c 100644
--- a/lib/rules/no-return-await.js
+++ b/lib/rules/no-return-await.js
@@ -18,7 +18,6 @@ module.exports = {
             description: "disallow unnecessary `return await`",
             category: "Best Practices",
 
-            // TODO: set to true
             recommended: false,
 
             url: "https://eslint.org/docs/rules/no-return-await"
diff --git a/lib/rules/no-shadow.js b/lib/rules/no-shadow.js
index d01231ff9..17ca1291d 100644
--- a/lib/rules/no-shadow.js
+++ b/lib/rules/no-shadow.js
@@ -179,7 +179,7 @@ module.exports = {
                 while (stack.length) {
                     const scope = stack.pop();
 
-                    stack.push.apply(stack, scope.childScopes);
+                    stack.push(...scope.childScopes);
                     checkForShadows(scope);
                 }
             }
diff --git a/lib/rules/no-undefined.js b/lib/rules/no-undefined.js
index 94b514e91..8491ab5d5 100644
--- a/lib/rules/no-undefined.js
+++ b/lib/rules/no-undefined.js
@@ -68,7 +68,7 @@ module.exports = {
                 while (stack.length) {
                     const scope = stack.pop();
 
-                    stack.push.apply(stack, scope.childScopes);
+                    stack.push(...scope.childScopes);
                     checkScope(scope);
                 }
             }
diff --git a/lib/rules/no-unused-vars.js b/lib/rules/no-unused-vars.js
index 6ba573498..0d5194bc8 100644
--- a/lib/rules/no-unused-vars.js
+++ b/lib/rules/no-unused-vars.js
@@ -457,30 +457,19 @@ module.exports = {
         }
 
         /**
-         * Checks whether the given variable is the last parameter in the non-ignored parameters.
+         * Checks whether the given variable is after the last used parameter.
          *
          * @param {eslint-scope.Variable} variable - The variable to check.
-         * @returns {boolean} `true` if the variable is the last.
+         * @returns {boolean} `true` if the variable is defined after the last
+         * used parameter.
          */
-        function isLastInNonIgnoredParameters(variable) {
+        function isAfterLastUsedArg(variable) {
             const def = variable.defs[0];
+            const params = context.getDeclaredVariables(def.node);
+            const posteriorParams = params.slice(params.indexOf(variable) + 1);
 
-            // This is the last.
-            if (def.index === def.node.params.length - 1) {
-                return true;
-            }
-
-            // if all parameters preceded by this variable are ignored and unused, this is the last.
-            if (config.argsIgnorePattern) {
-                const params = context.getDeclaredVariables(def.node);
-                const posteriorParams = params.slice(params.indexOf(variable) + 1);
-
-                if (posteriorParams.every(v => v.references.length === 0 && config.argsIgnorePattern.test(v.name))) {
-                    return true;
-                }
-            }
-
-            return false;
+            // If any used parameters occur after this parameter, do not report.
+            return !posteriorParams.some(v => v.references.length > 0);
         }
 
         /**
@@ -549,8 +538,8 @@ module.exports = {
                                 continue;
                             }
 
-                            // if "args" option is "after-used", skip all but the last parameter
-                            if (config.args === "after-used" && astUtils.isFunction(def.name.parent) && !isLastInNonIgnoredParameters(variable)) {
+                            // if "args" option is "after-used", skip used variables
+                            if (config.args === "after-used" && astUtils.isFunction(def.name.parent) && !isAfterLastUsedArg(variable)) {
                                 continue;
                             }
                         } else {
diff --git a/lib/timing.js b/lib/timing.js
index 9452e419b..102a5233d 100644
--- a/lib/timing.js
+++ b/lib/timing.js
@@ -116,10 +116,10 @@ module.exports = (function() {
             data[key] = 0;
         }
 
-        return function() {
+        return function(...args) {
             let t = process.hrtime();
 
-            fn.apply(null, Array.prototype.slice.call(arguments));
+            fn(...args);
             t = process.hrtime(t);
             data[key] += t[0] * 1e3 + t[1] / 1e6;
         };
diff --git a/lib/util/ajv.js b/lib/util/ajv.js
index f9e8b9853..285176da8 100644
--- a/lib/util/ajv.js
+++ b/lib/util/ajv.js
@@ -19,7 +19,8 @@ const ajv = new Ajv({
     meta: false,
     validateSchema: false,
     missingRefs: "ignore",
-    verbose: true
+    verbose: true,
+    schemaId: "auto"
 });
 
 ajv.addMetaSchema(metaSchema);
diff --git a/lib/util/safe-emitter.js b/lib/util/safe-emitter.js
index 2fa373cb9..ab212230d 100644
--- a/lib/util/safe-emitter.js
+++ b/lib/util/safe-emitter.js
@@ -27,8 +27,6 @@
  * another module throws an error or registers a listener.
  * 2. It calls listener functions without any `this` value. (`EventEmitter` calls listeners with a
  * `this` value of the emitter instance, which would give listeners access to other listeners.)
- * 3. Events can be emitted with at most 3 arguments. (For example: when using `emitter.emit('foo', a, b, c)`,
- * the arguments `a`, `b`, and `c` will be passed to the listener functions.)
  * @returns {SafeEmitter} An emitter
  */
 module.exports = () => {
@@ -42,9 +40,9 @@ module.exports = () => {
                 listeners[eventName] = [listener];
             }
         },
-        emit(eventName, a, b, c) {
+        emit(eventName, ...args) {
             if (eventName in listeners) {
-                listeners[eventName].forEach(listener => listener(a, b, c));
+                listeners[eventName].forEach(listener => listener(...args));
             }
         },
         eventNames() {
diff --git a/package.json b/package.json
index fd3b45874..104535daa 100644
--- a/package.json
+++ b/package.json
@@ -34,11 +34,11 @@
   "homepage": "https://eslint.org",
   "bugs": "https://github.com/eslint/eslint/issues/",
   "dependencies": {
-    "ajv": "^5.3.0",
+    "ajv": "^6.0.1",
     "babel-code-frame": "^6.26.0",
     "chalk": "^2.1.0",
     "concat-stream": "^1.6.2",
-    "cross-spawn": "^5.1.0",
+    "cross-spawn": "^6.0.5",
     "debug": "^3.1.0",
     "doctrine": "^2.1.0",
     "eslint-scope": "^3.7.1",
@@ -52,7 +52,7 @@
     "globals": "^11.4.0",
     "ignore": "^3.3.3",
     "imurmurhash": "^0.1.4",
-    "inquirer": "^3.3.0",
+    "inquirer": "^5.2.0",
     "is-resolvable": "^1.1.0",
     "js-yaml": "^3.11.0",
     "json-stable-stringify-without-jsonify": "^1.0.1",
@@ -70,13 +70,14 @@
     "semver": "^5.5.0",
     "strip-ansi": "^4.0.0",
     "strip-json-comments": "^2.0.1",
-    "table": "4.0.2",
+    "table": "^4.0.3",
     "text-table": "^0.2.0"
   },
   "devDependencies": {
+    "babel-core": "^6.26.0",
     "babel-polyfill": "^6.26.0",
     "babel-preset-es2015": "^6.24.1",
-    "babelify": "^7.3.0",
+    "babelify": "^8.0.0",
     "beefy": "^2.1.8",
     "brfs": "^1.5.0",
     "browserify": "^16.1.1",
@@ -121,6 +122,6 @@
   ],
   "license": "MIT",
   "engines": {
-    "node": ">=4"
+    "node": "^6.14.0 || ^8.10.0 || >=9.10.0"
   }
 }
diff --git a/packages/eslint-config-eslint/default.yml b/packages/eslint-config-eslint/default.yml
index a2f9ed742..8c5ac071c 100644
--- a/packages/eslint-config-eslint/default.yml
+++ b/packages/eslint-config-eslint/default.yml
@@ -152,11 +152,14 @@ rules:
     prefer-const: "error"
     prefer-numeric-literals: "error"
     prefer-promise-reject-errors: "error"
+    prefer-rest-params: "error"
+    prefer-spread: "error"
     prefer-template: "error"
     quotes: ["error", "double"]
     quote-props: ["error", "as-needed"]
     radix: "error"
     require-jsdoc: "error"
+    rest-spread-spacing: "error"
     semi: "error"
     semi-spacing: ["error", {before: false, after: true}]
     semi-style: "error"


Test patch:
diff --git a/tests/lib/ast-utils.js b/tests/lib/ast-utils.js
index 538b941cd..c728b8457 100644
--- a/tests/lib/ast-utils.js
+++ b/tests/lib/ast-utils.js
@@ -42,10 +42,10 @@ describe("ast-utils", () => {
      */
     function mustCall(func) {
         callCounts.set(func, 0);
-        return function Wrapper() {
+        return function Wrapper(...args) {
             callCounts.set(func, callCounts.get(func) + 1);
 
-            return func.apply(this, arguments);
+            return func.call(this, ...args);
         };
     }
 
diff --git a/tests/lib/cli-engine.js b/tests/lib/cli-engine.js
index 54f018da0..acbdba72d 100644
--- a/tests/lib/cli-engine.js
+++ b/tests/lib/cli-engine.js
@@ -46,15 +46,11 @@ describe("CLIEngine", () => {
      * @returns {string} The path inside the fixture directory.
      * @private
      */
-    function getFixturePath() {
-        const args = Array.prototype.slice.call(arguments);
-
-        args.unshift(fixtureDir);
-        let filepath = path.join.apply(path, args);
+    function getFixturePath(...args) {
+        const filepath = path.join(fixtureDir, ...args);
 
         try {
-            filepath = fs.realpathSync(filepath);
-            return filepath;
+            return fs.realpathSync(filepath);
         } catch (e) {
             return filepath;
         }
@@ -565,11 +561,11 @@ describe("CLIEngine", () => {
             /* eslint-disable no-underscore-dangle */
             before(() => {
                 originalFindPath = Module._findPath;
-                Module._findPath = function(id) {
+                Module._findPath = function(id, ...otherArgs) {
                     if (id === "@scope/eslint-plugin") {
                         return path.resolve(__dirname, "../fixtures/plugin-shorthand/basic/node_modules/@scope/eslint-plugin/index.js");
                     }
-                    return originalFindPath.apply(this, arguments);
+                    return originalFindPath.call(this, id, ...otherArgs);
                 };
             });
             after(() => {
diff --git a/tests/lib/cli.js b/tests/lib/cli.js
index 7c8801b72..04a966c81 100644
--- a/tests/lib/cli.js
+++ b/tests/lib/cli.js
@@ -72,11 +72,8 @@ describe("cli", () => {
      * @returns {string} The path inside the fixture directory.
      * @private
      */
-    function getFixturePath() {
-        const args = Array.prototype.slice.call(arguments);
-
-        args.unshift(fixtureDir);
-        return path.join.apply(path, args);
+    function getFixturePath(...args) {
+        return path.join(fixtureDir, ...args);
     }
 
     // copy into clean area so as not to get "infected" by this project's .eslintrc files
diff --git a/tests/lib/config.js b/tests/lib/config.js
index 9b7458db1..1f9690339 100644
--- a/tests/lib/config.js
+++ b/tests/lib/config.js
@@ -97,12 +97,8 @@ describe("Config", () => {
      * @returns {string} The path inside the fixture directory.
      * @private
      */
-    function getFixturePath() {
-        const args = Array.prototype.slice.call(arguments);
-
-        args.unshift("config-hierarchy");
-        args.unshift(fixtureDir);
-        return path.join.apply(path, args);
+    function getFixturePath(...args) {
+        return path.join(fixtureDir, "config-hierarchy", ...args);
     }
 
     /**
@@ -184,14 +180,8 @@ describe("Config", () => {
          * @returns {string} The path inside the fixture directory.
          * @private
          */
-        function getFakeFixturePath() {
-            const args = Array.prototype.slice.call(arguments);
-
-            args.unshift("config-hierarchy");
-            args.unshift("fixtures");
-            args.unshift("eslint");
-            args.unshift(process.cwd());
-            return path.join.apply(path, args);
+        function getFakeFixturePath(...args) {
+            return path.join(process.cwd(), "eslint", "fixtures", "config-hierarchy", ...args);
         }
 
         before(() => {
@@ -834,14 +824,8 @@ describe("Config", () => {
              * @returns {string} The path inside the fixture directory.
              * @private
              */
-            function getFakeFixturePath() {
-                const args = Array.prototype.slice.call(arguments);
-
-                args.unshift("config-hierarchy");
-                args.unshift("fixtures");
-                args.unshift("eslint");
-                args.unshift(process.cwd());
-                return path.join.apply(path, args);
+            function getFakeFixturePath(...args) {
+                return path.join(process.cwd(), "eslint", "fixtures", "config-hierarchy", ...args);
             }
 
             /**
@@ -979,14 +963,8 @@ describe("Config", () => {
              * @returns {string} The path inside the fixture directory.
              * @private
              */
-            function getFakeFixturePath() {
-                const args = Array.prototype.slice.call(arguments);
-
-                args.unshift("config-hierarchy");
-                args.unshift("fixtures");
-                args.unshift("eslint");
-                args.unshift(process.cwd());
-                return path.join.apply(path, args);
+            function getFakeFixturePath(...args) {
+                return path.join(process.cwd(), "eslint", "fixtures", "config-hierarchy", ...args);
             }
 
             /**
@@ -1117,15 +1095,8 @@ describe("Config", () => {
              * @returns {string} The path inside the fixture directory.
              * @private
              */
-            function getFakeFixturePath() {
-                const pathSegments = Array.from(arguments);
-
-                pathSegments.unshift("config-hierarchy");
-                pathSegments.unshift("fixtures");
-                pathSegments.unshift("eslint");
-                pathSegments.unshift(process.cwd());
-
-                return path.join.apply(path, pathSegments);
+            function getFakeFixturePath(...pathSegments) {
+                return path.join(process.cwd(), "eslint", "fixtures", "config-hierarchy", ...pathSegments);
             }
 
             before(() => {
diff --git a/tests/lib/config/config-initializer.js b/tests/lib/config/config-initializer.js
index e1a24dc36..ceeed0cb3 100644
--- a/tests/lib/config/config-initializer.js
+++ b/tests/lib/config/config-initializer.js
@@ -64,15 +64,11 @@ describe("configInitializer", () => {
      * @returns {string} The path inside the fixture directory.
      * @private
      */
-    function getFixturePath() {
-        const args = Array.prototype.slice.call(arguments);
-
-        args.unshift(fixtureDir);
-        let filepath = path.join.apply(path, args);
+    function getFixturePath(...args) {
+        const filepath = path.join(fixtureDir, ...args);
 
         try {
-            filepath = fs.realpathSync(filepath);
-            return filepath;
+            return fs.realpathSync(filepath);
         } catch (e) {
             return filepath;
         }
@@ -316,6 +312,7 @@ describe("configInitializer", () => {
         describe("auto", () => {
             const completeSpy = sinon.spy();
             let config;
+            let sandbox;
 
             before(() => {
                 const patterns = [
@@ -334,23 +331,21 @@ describe("configInitializer", () => {
                     commonjs: false
                 };
 
-                const sandbox = sinon.sandbox.create();
-
+                sandbox = sinon.sandbox.create();
                 sandbox.stub(console, "log"); // necessary to replace, because of progress bar
 
                 process.chdir(fixtureDir);
+                config = init.processAnswers(answers);
+                sandbox.restore();
+            });
 
-                try {
-                    config = init.processAnswers(answers);
-                    process.chdir(originalDir);
-                } catch (err) {
-
-                    // if processAnswers crashes, we need to be sure to restore cwd
-                    process.chdir(originalDir);
-                    throw err;
-                } finally {
-                    sandbox.restore(); // restore console.log()
-                }
+            after(() => {
+                sandbox.restore();
+            });
+
+            afterEach(() => {
+                process.chdir(originalDir);
+                sandbox.restore();
             });
 
             it("should create a config", () => {
@@ -371,25 +366,21 @@ describe("configInitializer", () => {
             it("should throw on fatal parsing error", () => {
                 const filename = getFixturePath("parse-error");
 
-                sinon.stub(autoconfig, "extendFromRecommended");
+                sandbox.stub(autoconfig, "extendFromRecommended");
                 answers.patterns = filename;
                 process.chdir(fixtureDir);
                 assert.throws(() => {
                     config = init.processAnswers(answers);
                 }, "Parsing error: Unexpected token ;");
-                process.chdir(originalDir);
-                autoconfig.extendFromRecommended.restore();
             });
 
             it("should throw if no files are matched from patterns", () => {
-                sinon.stub(autoconfig, "extendFromRecommended");
+                sandbox.stub(autoconfig, "extendFromRecommended");
                 answers.patterns = "not-a-real-filename";
                 process.chdir(fixtureDir);
                 assert.throws(() => {
                     config = init.processAnswers(answers);
                 }, "Automatic Configuration failed.  No files were able to be parsed.");
-                process.chdir(originalDir);
-                autoconfig.extendFromRecommended.restore();
             });
         });
     });
diff --git a/tests/lib/ignored-paths.js b/tests/lib/ignored-paths.js
index d7e077fe1..42fe5e0e3 100644
--- a/tests/lib/ignored-paths.js
+++ b/tests/lib/ignored-paths.js
@@ -95,11 +95,8 @@ function countDefaultPatterns(ignoredPaths) {
  * @returns {string} The path inside the fixture directory.
  * @private
  */
-function getFixturePath() {
-    const args = Array.prototype.slice.call(arguments);
-
-    args.unshift(fs.realpathSync(fixtureDir));
-    return path.join.apply(path, args);
+function getFixturePath(...args) {
+    return path.join(fs.realpathSync(fixtureDir), ...args);
 }
 
 //------------------------------------------------------------------------------
diff --git a/tests/lib/rules/no-unused-vars.js b/tests/lib/rules/no-unused-vars.js
index 3f529aa39..f188f8ce3 100644
--- a/tests/lib/rules/no-unused-vars.js
+++ b/tests/lib/rules/no-unused-vars.js
@@ -596,25 +596,59 @@ ruleTester.run("no-unused-vars", rule, {
         {
             code: "(function(a, b, c) {})",
             options: [{ argsIgnorePattern: "c" }],
-            errors: [{ message: "'b' is defined but never used. Allowed unused args must match /c/." }]
+            errors: [
+                {
+                    message: "'a' is defined but never used. Allowed unused args must match /c/."
+                },
+                {
+                    message: "'b' is defined but never used. Allowed unused args must match /c/."
+                }
+            ]
         },
         {
             code: "(function(a, b, {c, d}) {})",
             options: [{ argsIgnorePattern: "[cd]" }],
             parserOptions: { ecmaVersion: 6 },
-            errors: [{ message: "'b' is defined but never used. Allowed unused args must match /[cd]/." }]
+            errors: [
+                {
+                    message: "'a' is defined but never used. Allowed unused args must match /[cd]/."
+                },
+                {
+                    message: "'b' is defined but never used. Allowed unused args must match /[cd]/."
+                }
+            ]
         },
         {
             code: "(function(a, b, {c, d}) {})",
             options: [{ argsIgnorePattern: "c" }],
             parserOptions: { ecmaVersion: 6 },
-            errors: [{ message: "'d' is defined but never used. Allowed unused args must match /c/." }]
+            errors: [
+                {
+                    message: "'a' is defined but never used. Allowed unused args must match /c/."
+                },
+                {
+                    message: "'b' is defined but never used. Allowed unused args must match /c/."
+                },
+                {
+                    message: "'d' is defined but never used. Allowed unused args must match /c/."
+                }
+            ]
         },
         {
             code: "(function(a, b, {c, d}) {})",
             options: [{ argsIgnorePattern: "d" }],
             parserOptions: { ecmaVersion: 6 },
-            errors: [{ message: "'c' is defined but never used. Allowed unused args must match /d/." }]
+            errors: [
+                {
+                    message: "'a' is defined but never used. Allowed unused args must match /d/."
+                },
+                {
+                    message: "'b' is defined but never used. Allowed unused args must match /d/."
+                },
+                {
+                    message: "'c' is defined but never used. Allowed unused args must match /d/."
+                }
+            ]
         },
         {
             code: "/*global\rfoo*/",
diff --git a/tests/lib/util/glob-util.js b/tests/lib/util/glob-util.js
index d4ac651b8..47c601d26 100644
--- a/tests/lib/util/glob-util.js
+++ b/tests/lib/util/glob-util.js
@@ -26,11 +26,8 @@ let fixtureDir;
  * @returns {string} The path inside the fixture directory.
  * @private
  */
-function getFixturePath() {
-    const args = Array.prototype.slice.call(arguments);
-
-    args.unshift(fs.realpathSync(fixtureDir));
-    return path.join.apply(path, args);
+function getFixturePath(...args) {
+    return path.join(fs.realpathSync(fixtureDir), ...args);
 }
 
 //------------------------------------------------------------------------------
diff --git a/tests/lib/util/source-code-util.js b/tests/lib/util/source-code-util.js
index 44bb6613d..374443321 100644
--- a/tests/lib/util/source-code-util.js
+++ b/tests/lib/util/source-code-util.js
@@ -35,11 +35,8 @@ describe("SourceCodeUtil", () => {
      * @returns {string} The path inside the fixture directory.
      * @private
      */
-    function getFixturePath() {
-        const args = Array.prototype.slice.call(arguments);
-
-        args.unshift(fixtureDir);
-        let filepath = path.join.apply(path, args);
+    function getFixturePath(...args) {
+        let filepath = path.join(fixtureDir, ...args);
 
         try {
             filepath = fs.realpathSync(filepath);