Repository: eslint/eslint
Pull request #10219 (2018-04-15 11:43:45)

Docs: make template links wording more clearer
<!--
    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)**

[x] 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
[ ] Other, please explain:

<!--
    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)**

This wording would help me find the actual template before proposing new rule.

**Is there anything you'd like reviewers to focus on?**


PR migrated from https://github.com/eslint/eslint.github.io/pull/462#issuecomment-381397073



Patch:
diff --git a/README.md b/README.md
index ed991e14f..cb8c0277d 100644
--- a/README.md
+++ b/README.md
@@ -113,19 +113,15 @@ Before filing an issue, please be sure to read the guidelines for what you're re
 
 ## Frequently Asked Questions
 
-### I heard ESLint is going to replace JSCS?
+### I'm using JSCS, should I migrate to ESLint?
 
-Yes. Since we are solving the same problems, ESLint and JSCS teams have decided to join forces and work together in the development of ESLint instead of competing with each other. You can read more about this in both [ESLint](https://eslint.org/blog/2016/04/welcoming-jscs-to-eslint) and [JSCS](https://medium.com/@markelog/jscs-end-of-the-line-bc9bf0b3fdb2#.u76sx334n) announcements.
+Maybe, depending on how much you need it. [JSCS has reached end of life](https://eslint.org/blog/2016/07/jscs-end-of-life), but if it is working for you then there is no reason to move yet. There are still [a few issues](https://github.com/eslint/eslint/milestones/JSCS%20Compatibility) pending. We’ll announce when all of the changes necessary to support JSCS users in ESLint are complete and will start encouraging JSCS users to switch to ESLint at that time.
 
-### So, should I stop using JSCS and start using ESLint?
+If you are having issues with JSCS, you can try to move to ESLint. Have a look at our [migration guide](https://eslint.org/docs/user-guide/migrating-from-jscs).
 
-Maybe, depending on how much you need it. [JSCS has reached end of life](https://eslint.org/blog/2016/07/jscs-end-of-life), but if it is working for you then there is no reason to move yet. We are still working to smooth the transition. You can see our progress [here](https://github.com/eslint/eslint/milestones/JSCS%20Compatibility). We’ll announce when all of the changes necessary to support JSCS users in ESLint are complete and will start encouraging JSCS users to switch to ESLint at that time.
+### Does Prettier replace ESLint?
 
-If you are having issues with JSCS, you can try to move to ESLint. We are focusing our time and energy on JSCS compatibility issues.
-
-### Is ESLint just linting or does it also check style?
-
-ESLint does both traditional linting (looking for problematic patterns) and style checking (enforcement of conventions). You can use it for both.
+No, ESLint does both traditional linting (looking for problematic patterns) and style checking (enforcement of conventions). You can use ESLint for everything, or you can combine both using Prettier to format your code and ESLint to catch possible errors.
 
 ### Why can't ESLint find my plugins?
 
diff --git a/conf/eslint-recommended.js b/conf/eslint-recommended.js
index 0acee234a..df07c2e3c 100644
--- a/conf/eslint-recommended.js
+++ b/conf/eslint-recommended.js
@@ -39,14 +39,14 @@ module.exports = {
         "dot-notation": "off",
         "eol-last": "off",
         eqeqeq: "off",
-        "for-direction": "off",
+        "for-direction": "error",
         "func-call-spacing": "off",
         "func-name-matching": "off",
         "func-names": "off",
         "func-style": "off",
         "function-paren-newline": "off",
         "generator-star-spacing": "off",
-        "getter-return": "off",
+        "getter-return": "error",
         "global-require": "off",
         "guard-for-in": "off",
         "handle-callback-err": "off",
diff --git a/docs/developer-guide/contributing/new-rules.md b/docs/developer-guide/contributing/new-rules.md
index c3fe9f454..a3513773d 100644
--- a/docs/developer-guide/contributing/new-rules.md
+++ b/docs/developer-guide/contributing/new-rules.md
@@ -19,7 +19,7 @@ Even though these are the formal criteria for inclusion, each rule is evaluated
 
 ## Proposing a Rule
 
-If you want to propose a new rule, [create a pull request](/docs/developer-guide/contributing/pull-requests.md) or [new issue](https://github.com/eslint/eslint/issues/new?template=NEW_RULE.md) and fill out the template.
+If you want to propose a new rule, please see how to [create a pull request](/docs/developer-guide/contributing/pull-requests) or submit an issue by filling out a [new rule template](https://github.com/eslint/eslint/issues/new?template=NEW_RULE.md).
 
 We need all of this information in order to determine whether or not the rule is a good core rule candidate.
 
diff --git a/docs/rules/getter-return.md b/docs/rules/getter-return.md
index 57f92065d..c49f39dd2 100644
--- a/docs/rules/getter-return.md
+++ b/docs/rules/getter-return.md
@@ -74,7 +74,7 @@ class P{
 
 This rule has an object option:
 
-* `"allowImplicit": false` (default) disallows implicitly returning undefined with a return; statement.
+* `"allowImplicit": false` (default) disallows implicitly returning `undefined` with a `return` statement.
 
 Examples of **correct** code for the `{ "allowImplicit": true }` option:
 
diff --git a/docs/rules/no-mixed-spaces-and-tabs.md b/docs/rules/no-mixed-spaces-and-tabs.md
index 4f76b2617..ba34dbe49 100644
--- a/docs/rules/no-mixed-spaces-and-tabs.md
+++ b/docs/rules/no-mixed-spaces-and-tabs.md
@@ -41,7 +41,7 @@ function add(x, y) {
 
 This rule has a string option.
 
-* `"smart-tabs"` allows mixed spaces and tabs when the latter are used for alignment.
+* `"smart-tabs"` allows mixed tabs and spaces when the spaces are used for alignment.
 
 ### smart-tabs
 
diff --git a/docs/rules/valid-jsdoc.md b/docs/rules/valid-jsdoc.md
index 69375bf27..670f90fb9 100644
--- a/docs/rules/valid-jsdoc.md
+++ b/docs/rules/valid-jsdoc.md
@@ -158,7 +158,7 @@ This rule has an object option:
 * `"preferType"` enforces consistent type strings specified by an object whose properties mean instead of key use value (for example, `"object": "Object"` means instead of `object` use `Object`)
 * `"requireReturn"` requires a return tag:
     * `true` (default) **even if** the function or method does not have a `return` statement (this option value does not apply to constructors)
-    * `false` **if and only if** the function or method has a `return` statement (this option value does apply to constructors)
+    * `false` **if and only if** the function or method has a `return` statement or returns a value e.g. `async` function (this option value does apply to constructors)
 * `"requireReturnType": false` allows missing type in return tags
 * `"matchDescription"` specifies (as a string) a regular expression to match the description in each JSDoc comment (for example, `".+"` requires a description; this option does not apply to descriptions in parameter or return tags)
 * `"requireParamDescription": false` allows missing description in parameter tags
diff --git a/docs/user-guide/migrating-to-5.0.0.md b/docs/user-guide/migrating-to-5.0.0.md
index 73e17c7fc..4942b8749 100644
--- a/docs/user-guide/migrating-to-5.0.0.md
+++ b/docs/user-guide/migrating-to-5.0.0.md
@@ -7,6 +7,7 @@ The lists below are ordered roughly by the number of users each change is expect
 ### Breaking changes for users
 
 1. [Node.js 4 is no longer supported](#drop-node-4)
+1. [New rules have been added to `eslint:recommended`](#eslint-recommended-changes)
 1. [The `experimentalObjectRestSpread` option has been deprecated](#experimental-object-rest-spread)
 1. [Linting nonexistent files from the command line is now a fatal error](#nonexistent-files)
 1. [Deprecated globals have been removed from the `node`, `browser`, and `jest` environments](#deprecated-globals)
@@ -39,6 +40,26 @@ As of April 30th, 2018, Node.js 4 will be at EOL and will no longer be receiving
 
 **To address:** Make sure you upgrade to at least Node.js 6 when using ESLint v5. If you are unable to upgrade, we recommend continuing to use ESLint v4.x until you are able to upgrade Node.js.
 
+## <a name="eslint-recommended-changes"/> `eslint:recommended` changes
+
+Two new rules have been added to the [`eslint:recommended`](https://eslint.org/docs/user-guide/configuring#using-eslintrecommended) config:
+
+* [`for-direction`](/docs/rules/for-direction) enforce `for` loop update clause moving the counter in the right direction.
+* [`getter-return`](/docs/rules/getter-return) enforce a `return` statement is present in property getters.
+
+**To address:** To mimic the `eslint:recommended` behavior from 4.x, you can disable these rules in a config file:
+
+```json
+{
+  "extends": "eslint:recommended",
+
+  "rules": {
+    "for-direction": "off",
+    "getter-return": "off"
+  }
+}
+```
+
 ## <a name="experimental-object-rest-spread"></a> The `experimentalObjectRestSpread` option has been deprecated
 
 Previously, when using the default parser it was possible to use the `experimentalObjectRestSpread` option to enable support for [rest/spread properties](https://developers.google.com/web/updates/2017/06/object-rest-spread), as follows:
@@ -133,7 +154,7 @@ When it encounters a plugin name in a config starting with `@`, ESLint v5 will r
 
 Previously, ESLint would set the `parent` property on each AST node immediately before running rule listeners for that node. This caused some confusion for rule authors, because the `parent` property would not initially be present on any nodes, and it was sometimes necessary to complicate the structure of a rule to ensure that the `parent` property of a given node would be available when needed.
 
-In ESLint v5, the `parent` property is set on all AST nodes before any rules have access to the AST. This makes it easier to write some rules, because the `parent` property is always available rather than being mutated behind the scenes. However, as a side-effect of having `parent` properties, the AST object has a circular structure the first time a rule sees it (previously, it only had a circular structure after the first rule listeners were called). As a result, a custom rule that enumerates all properties of an node in order to traverse the AST might now loop forever or run out of memory if it does not check for cycles properly.
+In ESLint v5, the `parent` property is set on all AST nodes before any rules have access to the AST. This makes it easier to write some rules, because the `parent` property is always available rather than being mutated behind the scenes. However, as a side-effect of having `parent` properties, the AST object has a circular structure the first time a rule sees it (previously, it only had a circular structure after the first rule listeners were called). As a result, a custom rule that enumerates all properties of a node in order to traverse the AST might now loop forever or run out of memory if it does not check for cycles properly.
 
 **To address:** If you have written a custom rule that enumerates all properties of an AST node, consider excluding the `parent` property or implementing cycle detection to ensure that you obtain the correct result.
 
diff --git a/lib/cli-engine.js b/lib/cli-engine.js
index 8531d1c1d..c7bfb3626 100644
--- a/lib/cli-engine.js
+++ b/lib/cli-engine.js
@@ -481,7 +481,7 @@ class CLIEngine {
      * @returns {string[]} The equivalent glob patterns.
      */
     resolveFileGlobPatterns(patterns) {
-        return globUtil.resolveFileGlobPatterns(patterns, this.options);
+        return globUtil.resolveFileGlobPatterns(patterns.filter(Boolean), this.options);
     }
 
     /**
@@ -515,7 +515,7 @@ class CLIEngine {
         }
 
         const startTime = Date.now();
-        const fileList = globUtil.listFilesToProcess(this.resolveFileGlobPatterns(patterns), options);
+        const fileList = globUtil.listFilesToProcess(patterns, options);
         const results = fileList.map(fileInfo => {
             if (fileInfo.ignored) {
                 return createIgnoreResult(fileInfo.filename, options.cwd);
diff --git a/lib/config/config-file.js b/lib/config/config-file.js
index 37ac84831..46d561516 100644
--- a/lib/config/config-file.js
+++ b/lib/config/config-file.js
@@ -467,7 +467,7 @@ function resolve(filePath, relativeTo) {
         debug(`Attempting to resolve ${normalizedPackageName}`);
 
         return {
-            filePath: resolver.resolve(normalizedPackageName, getLookupPath(relativeTo)),
+            filePath: require.resolve(normalizedPackageName),
             configName,
             configFullName
         };
diff --git a/lib/config/config-validator.js b/lib/config/config-validator.js
index 1a5b3ef13..ed9a34cb0 100644
--- a/lib/config/config-validator.js
+++ b/lib/config/config-validator.js
@@ -9,7 +9,8 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const ajv = require("../util/ajv"),
+const path = require("path"),
+    ajv = require("../util/ajv"),
     lodash = require("lodash"),
     configSchema = require("../../conf/config-schema.js"),
     util = require("util");
@@ -21,6 +22,12 @@ const ruleValidators = new WeakMap();
 //------------------------------------------------------------------------------
 let validateSchema;
 
+// Defitions for deprecation warnings.
+const deprecationWarningMessages = Object.freeze({
+    ESLINT_LEGACY_ECMAFEATURES: "The 'ecmaFeatures' config file property is deprecated, and has no effect.",
+    ESLINT_LEGACY_OBJECT_REST_SPREAD: "The 'parserOptions.ecmaFeatures.experimentalObjectRestSpread' option is deprecated. Use 'parserOptions.ecmaVersion' instead."
+});
+
 /**
  * Gets a complete options schema for a rule.
  * @param {{create: Function, schema: (Array|null)}} rule A new-style rule object
@@ -194,18 +201,18 @@ function formatErrors(errors) {
  * for each unique file path, but repeated invocations with the same file path have no effect.
  * No warnings are emitted if the `--no-deprecation` or `--no-warnings` Node runtime flags are active.
  * @param {string} source The name of the configuration source to report the warning for.
+ * @param {string} errorCode The warning message to show.
  * @returns {void}
  */
-const emitEcmaFeaturesWarning = lodash.memoize(source => {
-
-    /*
-     * util.deprecate seems to be the only way to emit a warning in Node 4.x while respecting the --no-warnings flag.
-     * (In Node 6+, process.emitWarning could be used instead.)
-     */
-    util.deprecate(
-        () => {},
-        `[eslint] The 'ecmaFeatures' config file property is deprecated, and has no effect. (found in ${source})`
-    )();
+const emitDeprecationWarning = lodash.memoize((source, errorCode) => {
+    const rel = path.relative(process.cwd(), source);
+    const message = deprecationWarningMessages[errorCode];
+
+    process.emitWarning(
+        `${message} (found in "${rel}")`,
+        "DeprecationWarning",
+        errorCode
+    );
 });
 
 /**
@@ -221,8 +228,17 @@ function validateConfigSchema(config, source) {
         throw new Error(`ESLint configuration in ${source} is invalid:\n${formatErrors(validateSchema.errors)}`);
     }
 
-    if (Object.prototype.hasOwnProperty.call(config, "ecmaFeatures")) {
-        emitEcmaFeaturesWarning(source);
+    if (Object.hasOwnProperty.call(config, "ecmaFeatures")) {
+        emitDeprecationWarning(source, "ESLINT_LEGACY_ECMAFEATURES");
+    }
+
+    if (
+        (config.parser || "espree") === "espree" &&
+        config.parserOptions &&
+        config.parserOptions.ecmaFeatures &&
+        config.parserOptions.ecmaFeatures.experimentalObjectRestSpread
+    ) {
+        emitDeprecationWarning(source, "ESLINT_LEGACY_OBJECT_REST_SPREAD");
     }
 }
 
diff --git a/lib/linter.js b/lib/linter.js
index 7ca835c15..ec4b4f6d9 100644
--- a/lib/linter.js
+++ b/lib/linter.js
@@ -410,11 +410,12 @@ function normalizeVerifyOptions(providedOptions) {
 
 /**
  * Combines the provided parserOptions with the options from environments
+ * @param {string} parserName The parser name which uses this options.
  * @param {Object} providedOptions The provided 'parserOptions' key in a config
  * @param {Environment[]} enabledEnvironments The environments enabled in configuration and with inline comments
  * @returns {Object} Resulting parser options after merge
  */
-function resolveParserOptions(providedOptions, enabledEnvironments) {
+function resolveParserOptions(parserName, providedOptions, enabledEnvironments) {
     const parserOptionsFromEnv = enabledEnvironments
         .filter(env => env.parserOptions)
         .reduce((parserOptions, env) => ConfigOps.merge(parserOptions, env.parserOptions), {});
@@ -431,6 +432,16 @@ function resolveParserOptions(providedOptions, enabledEnvironments) {
 
     mergedParserOptions.ecmaVersion = normalizeEcmaVersion(mergedParserOptions.ecmaVersion, isModule);
 
+    // TODO: For backward compatibility. Will remove on v6.0.0.
+    if (
+        parserName === DEFAULT_PARSER_NAME &&
+        mergedParserOptions.ecmaFeatures &&
+        mergedParserOptions.ecmaFeatures.experimentalObjectRestSpread &&
+        (!mergedParserOptions.ecmaVersion || mergedParserOptions.ecmaVersion < 9)
+    ) {
+        mergedParserOptions.ecmaVersion = 9;
+    }
+
     return mergedParserOptions;
 }
 
@@ -923,9 +934,9 @@ module.exports = class Linter {
             .map(envName => this.environments.get(envName))
             .filter(env => env);
 
-        const parserOptions = resolveParserOptions(config.parserOptions || {}, enabledEnvs);
-        const configuredGlobals = resolveGlobals(config.globals || {}, enabledEnvs);
         const parserName = config.parser || DEFAULT_PARSER_NAME;
+        const parserOptions = resolveParserOptions(parserName, config.parserOptions || {}, enabledEnvs);
+        const configuredGlobals = resolveGlobals(config.globals || {}, enabledEnvs);
         const settings = config.settings || {};
 
         if (!lastSourceCodes.get(this)) {
diff --git a/lib/rules/for-direction.js b/lib/rules/for-direction.js
index c91888da2..817e2c111 100644
--- a/lib/rules/for-direction.js
+++ b/lib/rules/for-direction.js
@@ -14,7 +14,7 @@ module.exports = {
         docs: {
             description: "enforce \"for\" loop update clause moving the counter in the right direction.",
             category: "Possible Errors",
-            recommended: false,
+            recommended: true,
             url: "https://eslint.org/docs/rules/for-direction"
         },
         fixable: null,
diff --git a/lib/rules/getter-return.js b/lib/rules/getter-return.js
index 58f2a3978..fe40e5f09 100644
--- a/lib/rules/getter-return.js
+++ b/lib/rules/getter-return.js
@@ -47,7 +47,7 @@ module.exports = {
         docs: {
             description: "enforce `return` statements in getters",
             category: "Possible Errors",
-            recommended: false,
+            recommended: true,
             url: "https://eslint.org/docs/rules/getter-return"
         },
         fixable: null,
diff --git a/lib/rules/object-shorthand.js b/lib/rules/object-shorthand.js
index c5239a71d..71a320a0e 100644
--- a/lib/rules/object-shorthand.js
+++ b/lib/rules/object-shorthand.js
@@ -233,6 +233,10 @@ module.exports = {
             const keyText = sourceCode.text.slice(firstKeyToken.range[0], lastKeyToken.range[1]);
             let keyPrefix = "";
 
+            if (sourceCode.commentsExistBetween(lastKeyToken, node.value)) {
+                return null;
+            }
+
             if (node.value.async) {
                 keyPrefix += "async ";
             }
diff --git a/lib/rules/valid-jsdoc.js b/lib/rules/valid-jsdoc.js
index 4038f70e5..971e755c4 100644
--- a/lib/rules/valid-jsdoc.js
+++ b/lib/rules/valid-jsdoc.js
@@ -102,7 +102,7 @@ module.exports = {
         function startFunction(node) {
             fns.push({
                 returnPresent: (node.type === "ArrowFunctionExpression" && node.body.type !== "BlockStatement") ||
-                    isTypeClass(node)
+                    isTypeClass(node) || node.async
             });
         }
 
diff --git a/lib/util/glob-util.js b/lib/util/glob-util.js
index b91ec53e6..36cb9fcb6 100644
--- a/lib/util/glob-util.js
+++ b/lib/util/glob-util.js
@@ -22,6 +22,15 @@ const debug = require("debug")("eslint:glob-util");
 // Helpers
 //------------------------------------------------------------------------------
 
+/**
+ * Checks whether a directory exists at the given location
+ * @param {string} resolvedPath A path from the CWD
+ * @returns {boolean} `true` if a directory exists
+ */
+function directoryExists(resolvedPath) {
+    return fs.existsSync(resolvedPath) && fs.statSync(resolvedPath).isDirectory();
+}
+
 /**
  * Checks if a provided path is a directory and returns a glob string matching
  * all files under that directory if so, the path itself otherwise.
@@ -64,7 +73,7 @@ function processPath(options) {
         let newPath = pathname;
         const resolvedPath = path.resolve(cwd, pathname);
 
-        if (fs.existsSync(resolvedPath) && fs.statSync(resolvedPath).isDirectory()) {
+        if (directoryExists(resolvedPath)) {
             newPath = pathname.replace(/[/\\]$/, "") + suffix;
         }
 
@@ -72,6 +81,73 @@ function processPath(options) {
     };
 }
 
+/**
+ * The error type when no files match a glob.
+ */
+class NoFilesFoundError extends Error {
+
+    /**
+     * @param {string} pattern - The glob pattern which was not found.
+     */
+    constructor(pattern) {
+        super(`No files matching '${pattern}' were found.`);
+
+        this.messageTemplate = "file-not-found";
+        this.messageData = { pattern };
+    }
+
+}
+
+/**
+ * The error type when there are files matched by a glob, but all of them have been ignored.
+ */
+class AllFilesIgnoredError extends Error {
+
+    /**
+     * @param {string} pattern - The glob pattern which was not found.
+     */
+    constructor(pattern) {
+        super(`All files matched by '${pattern}' are ignored.`);
+        this.messageTemplate = "all-files-ignored";
+        this.messageData = { pattern };
+    }
+}
+
+const NORMAL_LINT = {};
+const SILENTLY_IGNORE = {};
+const IGNORE_AND_WARN = {};
+
+/**
+ * Tests whether a file should be linted or ignored
+ * @param {string} filename The file to be processed
+ * @param {{ignore: (boolean|null)}} options If `ignore` is false, updates the behavior to
+ * not process custom ignore paths, and lint files specified by direct path even if they
+ * match the default ignore path
+ * @param {boolean} isDirectPath True if the file was provided as a direct path
+ * (as opposed to being resolved from a glob)
+ * @param {IgnoredPaths} ignoredPaths An instance of IgnoredPaths to check whether a given
+ * file is ignored.
+ * @returns {(NORMAL_LINT|SILENTLY_IGNORE|IGNORE_AND_WARN)} A directive for how the
+ * file should be processed (either linted normally, or silently ignored, or ignored
+ * with a warning that it is being ignored)
+ */
+function testFileAgainstIgnorePatterns(filename, options, isDirectPath, ignoredPaths) {
+    const shouldProcessCustomIgnores = options.ignore !== false;
+    const shouldLintIgnoredDirectPaths = options.ignore === false;
+    const fileMatchesIgnorePatterns = ignoredPaths.contains(filename, "default") ||
+        (shouldProcessCustomIgnores && ignoredPaths.contains(filename, "custom"));
+
+    if (fileMatchesIgnorePatterns && isDirectPath && !shouldLintIgnoredDirectPaths) {
+        return IGNORE_AND_WARN;
+    }
+
+    if (!fileMatchesIgnorePatterns || (isDirectPath && shouldLintIgnoredDirectPaths)) {
+        return NORMAL_LINT;
+    }
+
+    return SILENTLY_IGNORE;
+}
+
 //------------------------------------------------------------------------------
 // Public Interface
 //------------------------------------------------------------------------------
@@ -86,7 +162,7 @@ function resolveFileGlobPatterns(patterns, options) {
 
     const processPathExtensions = processPath(options);
 
-    return patterns.filter(p => p.length).map(processPathExtensions);
+    return patterns.map(processPathExtensions);
 }
 
 const dotfilesPattern = /(?:(?:^\.)|(?:[/\\]\.))[^/\\.].*/;
@@ -105,9 +181,6 @@ const dotfilesPattern = /(?:(?:^\.)|(?:[/\\]\.))[^/\\.].*/;
  */
 function listFilesToProcess(globPatterns, providedOptions) {
     const options = providedOptions || { ignore: true };
-    const files = [];
-    const addedFilenames = new Set();
-
     const cwd = options.cwd || process.cwd();
 
     const getIgnorePaths = lodash.memoize(
@@ -115,69 +188,79 @@ function listFilesToProcess(globPatterns, providedOptions) {
             new IgnoredPaths(optionsObj)
     );
 
-    /**
-     * Executes the linter on a file defined by the `filename`. Skips
-     * any files that are already linted.
-     * @param {string} filename The file to be processed
-     * @param {boolean} isDirectPath True if the file
-     * was provided as a direct path (as opposed to being resolved from a glob)
-     * @param {IgnoredPaths} ignoredPaths An instance of IgnoredPaths
-     * @returns {void}
+    /*
+     * The test "should use default options if none are provided" (source-code-util.js) checks that 'module.exports.resolveFileGlobPatterns' was called.
+     * So it cannot use the local function "resolveFileGlobPatterns".
      */
-    function addFile(filename, isDirectPath, ignoredPaths) {
-        if (addedFilenames.has(filename)) {
-            return;
-        }
-
-        const shouldProcessCustomIgnores = options.ignore !== false;
-        const shouldLintIgnoredDirectPaths = options.ignore === false;
-        const fileMatchesIgnorePatterns = ignoredPaths.contains(filename, "default") ||
-            (shouldProcessCustomIgnores && ignoredPaths.contains(filename, "custom"));
-
-        if (fileMatchesIgnorePatterns && isDirectPath && !shouldLintIgnoredDirectPaths) {
-            files.push({ filename, ignored: true });
-            addedFilenames.add(filename);
-        }
-
-        if (!fileMatchesIgnorePatterns || (isDirectPath && shouldLintIgnoredDirectPaths)) {
-            files.push({ filename, ignored: false });
-            addedFilenames.add(filename);
-        }
-    }
+    const resolvedGlobPatterns = module.exports.resolveFileGlobPatterns(globPatterns, options);
 
     debug("Creating list of files to process.");
-    globPatterns.forEach(pattern => {
+    const resolvedPathsByGlobPattern = resolvedGlobPatterns.map(pattern => {
         const file = path.resolve(cwd, pattern);
 
         if (fs.existsSync(file) && fs.statSync(file).isFile()) {
             const ignoredPaths = getIgnorePaths(options);
+            const fullPath = fs.realpathSync(file);
+
+            return [{
+                filename: fullPath,
+                behavior: testFileAgainstIgnorePatterns(fullPath, options, true, ignoredPaths)
+            }];
+        }
 
-            addFile(fs.realpathSync(file), true, ignoredPaths);
-        } else {
+        // regex to find .hidden or /.hidden patterns, but not ./relative or ../relative
+        const globIncludesDotfiles = dotfilesPattern.test(pattern);
+        let newOptions = options;
 
-            // regex to find .hidden or /.hidden patterns, but not ./relative or ../relative
-            const globIncludesDotfiles = dotfilesPattern.test(pattern);
-            let newOptions = options;
+        if (!options.dotfiles) {
+            newOptions = Object.assign({}, options, { dotfiles: globIncludesDotfiles });
+        }
 
-            if (!options.dotfiles) {
-                newOptions = Object.assign({}, options, { dotfiles: globIncludesDotfiles });
-            }
+        const ignoredPaths = getIgnorePaths(newOptions);
+        const shouldIgnore = ignoredPaths.getIgnoredFoldersGlobChecker();
+        const globOptions = {
+            nodir: true,
+            dot: true,
+            cwd
+        };
 
-            const ignoredPaths = getIgnorePaths(newOptions);
-            const shouldIgnore = ignoredPaths.getIgnoredFoldersGlobChecker();
-            const globOptions = {
-                nodir: true,
-                dot: true,
-                cwd
+        return new GlobSync(pattern, globOptions, shouldIgnore).found.map(globMatch => {
+            const relativePath = path.resolve(cwd, globMatch);
+
+            return {
+                filename: relativePath,
+                behavior: testFileAgainstIgnorePatterns(relativePath, options, false, ignoredPaths)
             };
+        });
+    });
 
-            new GlobSync(pattern, globOptions, shouldIgnore).found.forEach(globMatch => {
-                addFile(path.resolve(cwd, globMatch), false, ignoredPaths);
-            });
+    const allPathDescriptors = resolvedPathsByGlobPattern.reduce((pathsForAllGlobs, pathsForCurrentGlob, index) => {
+        if (pathsForCurrentGlob.every(pathDescriptor => pathDescriptor.behavior === SILENTLY_IGNORE)) {
+            throw new (pathsForCurrentGlob.length ? AllFilesIgnoredError : NoFilesFoundError)(globPatterns[index]);
         }
-    });
 
-    return files;
+        pathsForCurrentGlob.forEach(pathDescriptor => {
+            switch (pathDescriptor.behavior) {
+                case NORMAL_LINT:
+                    pathsForAllGlobs.push({ filename: pathDescriptor.filename, ignored: false });
+                    break;
+                case IGNORE_AND_WARN:
+                    pathsForAllGlobs.push({ filename: pathDescriptor.filename, ignored: true });
+                    break;
+                case SILENTLY_IGNORE:
+
+                    // do nothing
+                    break;
+
+                default:
+                    throw new Error(`Unexpected file behavior for ${pathDescriptor.filename}`);
+            }
+        });
+
+        return pathsForAllGlobs;
+    }, []);
+
+    return lodash.uniqBy(allPathDescriptors, pathDescriptor => pathDescriptor.filename);
 }
 
 module.exports = {
diff --git a/lib/util/module-resolver.js b/lib/util/module-resolver.js
index 470a54f7c..1e9b66330 100644
--- a/lib/util/module-resolver.js
+++ b/lib/util/module-resolver.js
@@ -59,9 +59,7 @@ class ModuleResolver {
          * subsequent calls to this function. Then, move the extraLookupPath to the
          * top of the lookup paths list so it will be searched first.
          */
-        const lookupPaths = this.options.lookupPaths.concat();
-
-        lookupPaths.unshift(extraLookupPath);
+        const lookupPaths = [extraLookupPath, ...this.options.lookupPaths];
 
         /**
          * Module._findPath is an internal method to Node.js, then one they use to
diff --git a/lib/util/source-code-util.js b/lib/util/source-code-util.js
index 815fad911..66d91cd21 100644
--- a/lib/util/source-code-util.js
+++ b/lib/util/source-code-util.js
@@ -78,14 +78,13 @@ function getSourceCodeOfFiles(patterns, providedOptions, providedCallback) {
         callback = providedCallback;
     }
     debug("constructed options:", options);
-    const resolvedPatterns = globUtil.resolveFileGlobPatterns(globPatternsList, options);
 
-    const filenames = globUtil.listFilesToProcess(resolvedPatterns, options)
+    const filenames = globUtil.listFilesToProcess(globPatternsList, options)
         .filter(fileInfo => !fileInfo.ignored)
         .reduce((files, fileInfo) => files.concat(fileInfo.filename), []);
 
     if (filenames.length === 0) {
-        debug(`Did not find any files matching pattern(s): ${resolvedPatterns}`);
+        debug(`Did not find any files matching pattern(s): ${globPatternsList}`);
     }
     filenames.forEach(filename => {
         const sourceCode = getSourceCodeOfFile(filename, options);
diff --git a/messages/all-files-ignored.txt b/messages/all-files-ignored.txt
new file mode 100644
index 000000000..3b741a03e
--- /dev/null
+++ b/messages/all-files-ignored.txt
@@ -0,0 +1,8 @@
+All of the files matching the glob pattern "<%= pattern %>" are ignored.
+
+If you don't want to lint these files, remove the pattern "<%= pattern %>" from the list of arguments passed to ESLint.
+
+If you do want to lint these files, try the following solutions:
+
+* Check your .eslintignore file, or the eslintIgnore property in package.json, to ensure that the files are not configured to be ignored.
+* Explicitly list the files from this glob that you'd like to lint on the command-line, rather than providing a glob as an argument.
diff --git a/messages/file-not-found.txt b/messages/file-not-found.txt
new file mode 100644
index 000000000..97e2d37fa
--- /dev/null
+++ b/messages/file-not-found.txt
@@ -0,0 +1,2 @@
+No files matching the pattern "<%= pattern %>" were found.
+Please check for typing mistakes in the pattern.
diff --git a/package.json b/package.json
index e1199bb32..7007d48ba 100644
--- a/package.json
+++ b/package.json
@@ -90,7 +90,7 @@
     "eslint-plugin-rulesdir": "^0.1.0",
     "eslint-release": "^0.11.1",
     "eslint-rule-composer": "^0.1.1",
-    "eslump": "^1.6.1",
+    "eslump": "^1.6.2",
     "esprima": "^4.0.0",
     "istanbul": "^0.4.5",
     "jsdoc": "^3.5.5",
diff --git a/packages/eslint-config-eslint/default.yml b/packages/eslint-config-eslint/default.yml
index 8c5ac071c..611594067 100644
--- a/packages/eslint-config-eslint/default.yml
+++ b/packages/eslint-config-eslint/default.yml
@@ -24,12 +24,10 @@ rules:
     dot-notation: ["error", { allowKeywords: true }]
     eol-last: "error"
     eqeqeq: "error"
-    for-direction: "error"
     func-call-spacing: "error"
     func-style: ["error", "declaration"]
     function-paren-newline: ["error", "consistent"]
     generator-star-spacing: "error"
-    getter-return: "error"
     guard-for-in: "error"
     handle-callback-err: ["error", "err"]
     key-spacing: ["error", { beforeColon: false, afterColon: true }]
diff --git a/tools/eslint-fuzzer.js b/tools/eslint-fuzzer.js
index ea84e994b..342dee3e4 100644
--- a/tools/eslint-fuzzer.js
+++ b/tools/eslint-fuzzer.js
@@ -110,7 +110,7 @@ function fuzz(options) {
         const text = codeGenerator({ sourceType });
         const config = {
             rules: lodash.mapValues(ruleConfigs, lodash.sample),
-            parserOptions: { sourceType, ecmaVersion: 2017 }
+            parserOptions: { sourceType, ecmaVersion: 2018 }
         };
 
         let autofixResult;


Test patch:
diff --git a/tests/fixtures/cli-engine/empty/.keep b/tests/fixtures/cli-engine/empty/.keep
new file mode 100644
index 000000000..e69de29bb
diff --git a/tests/fixtures/config-file/experimental-object-rest-spread/another-parser/.eslintrc.yml b/tests/fixtures/config-file/experimental-object-rest-spread/another-parser/.eslintrc.yml
new file mode 100644
index 000000000..c64b2c309
--- /dev/null
+++ b/tests/fixtures/config-file/experimental-object-rest-spread/another-parser/.eslintrc.yml
@@ -0,0 +1,6 @@
+root: true
+
+parser: ./parser.js
+parserOptions:
+  ecmaFeatures:
+    experimentalObjectRestSpread: true
diff --git a/tests/fixtures/config-file/experimental-object-rest-spread/another-parser/parser.js b/tests/fixtures/config-file/experimental-object-rest-spread/another-parser/parser.js
new file mode 100644
index 000000000..f193589ef
--- /dev/null
+++ b/tests/fixtures/config-file/experimental-object-rest-spread/another-parser/parser.js
@@ -0,0 +1,1 @@
+module.exports.parse = () => ({ type: "Program", body: [] })
diff --git a/tests/fixtures/config-file/experimental-object-rest-spread/basic/.eslintrc.yml b/tests/fixtures/config-file/experimental-object-rest-spread/basic/.eslintrc.yml
new file mode 100644
index 000000000..a5c9e4ebf
--- /dev/null
+++ b/tests/fixtures/config-file/experimental-object-rest-spread/basic/.eslintrc.yml
@@ -0,0 +1,5 @@
+root: true
+
+parserOptions:
+  ecmaFeatures:
+    experimentalObjectRestSpread: true
diff --git a/tests/fixtures/config-file/experimental-object-rest-spread/extends/.eslintrc.yml b/tests/fixtures/config-file/experimental-object-rest-spread/extends/.eslintrc.yml
new file mode 100644
index 000000000..2daef0dea
--- /dev/null
+++ b/tests/fixtures/config-file/experimental-object-rest-spread/extends/.eslintrc.yml
@@ -0,0 +1,4 @@
+root: true
+
+extends:
+  - ./common.yml
diff --git a/tests/fixtures/config-file/experimental-object-rest-spread/extends/common.yml b/tests/fixtures/config-file/experimental-object-rest-spread/extends/common.yml
new file mode 100644
index 000000000..99975a7bd
--- /dev/null
+++ b/tests/fixtures/config-file/experimental-object-rest-spread/extends/common.yml
@@ -0,0 +1,3 @@
+parserOptions:
+  ecmaFeatures:
+    experimentalObjectRestSpread: true
diff --git a/tests/fixtures/config-file/experimental-object-rest-spread/subdir/.eslintrc.yml b/tests/fixtures/config-file/experimental-object-rest-spread/subdir/.eslintrc.yml
new file mode 100644
index 000000000..a5c9e4ebf
--- /dev/null
+++ b/tests/fixtures/config-file/experimental-object-rest-spread/subdir/.eslintrc.yml
@@ -0,0 +1,5 @@
+root: true
+
+parserOptions:
+  ecmaFeatures:
+    experimentalObjectRestSpread: true
diff --git a/tests/fixtures/config-file/experimental-object-rest-spread/subdir/lib/.eslintrc.yml b/tests/fixtures/config-file/experimental-object-rest-spread/subdir/lib/.eslintrc.yml
new file mode 100644
index 000000000..78dc43786
--- /dev/null
+++ b/tests/fixtures/config-file/experimental-object-rest-spread/subdir/lib/.eslintrc.yml
@@ -0,0 +1,2 @@
+rules:
+  no-undef: off
diff --git a/tests/fixtures/glob-util/empty/.gitkeep b/tests/fixtures/glob-util/empty/.gitkeep
new file mode 100644
index 000000000..e69de29bb
diff --git a/tests/lib/cli-engine.js b/tests/lib/cli-engine.js
index acbdba72d..ea920f317 100644
--- a/tests/lib/cli-engine.js
+++ b/tests/lib/cli-engine.js
@@ -767,9 +767,9 @@ describe("CLIEngine", () => {
                 cwd: getFixturePath("cli-engine")
             });
 
-            const report = engine.executeOnFiles(["node_modules"]);
-
-            assert.strictEqual(report.results.length, 0);
+            assert.throws(() => {
+                engine.executeOnFiles(["node_modules"]);
+            }, "All files matched by 'node_modules' are ignored.");
         });
 
         // https://github.com/eslint/eslint/issues/5547
@@ -780,9 +780,9 @@ describe("CLIEngine", () => {
                 ignore: false
             });
 
-            const report = engine.executeOnFiles(["node_modules"]);
-
-            assert.strictEqual(report.results.length, 0);
+            assert.throws(() => {
+                engine.executeOnFiles(["node_modules"]);
+            }, "All files matched by 'node_modules' are ignored.");
         });
 
         it("should not check .hidden files if they are passed explicitly without --no-ignore flag", () => {
@@ -1029,35 +1029,32 @@ describe("CLIEngine", () => {
 
         });
 
-        it("should return zero messages when given a directory with eslint excluded files in the directory", () => {
+        it("should throw an error when given a directory with all eslint excluded files in the directory", () => {
 
             engine = new CLIEngine({
                 ignorePath: getFixturePath(".eslintignore")
             });
 
-            const report = engine.executeOnFiles([getFixturePath("./")]);
-
-            assert.strictEqual(report.results.length, 0);
+            assert.throws(() => {
+                engine.executeOnFiles([getFixturePath("./")]);
+            }, `All files matched by '${getFixturePath("./")}' are ignored.`);
         });
 
-        it("should return zero messages when all given files are ignored", () => {
-            engine = new CLIEngine({
-                ignorePath: getFixturePath(".eslintignore")
-            });
-
-            const report = engine.executeOnFiles(["tests/fixtures/"]);
+        it("should throw an error when all given files are ignored", () => {
 
-            assert.strictEqual(report.results.length, 0);
+            assert.throws(() => {
+                engine.executeOnFiles(["tests/fixtures/"]);
+            }, "All files matched by 'tests/fixtures/' are ignored.");
         });
 
-        it("should return zero messages when all given files are ignored event with a `./` prefix", () => {
+        it("should throw an error when all given files are ignored even with a `./` prefix", () => {
             engine = new CLIEngine({
                 ignorePath: getFixturePath(".eslintignore")
             });
 
-            const report = engine.executeOnFiles(["./tests/fixtures/"]);
-
-            assert.strictEqual(report.results.length, 0);
+            assert.throws(() => {
+                engine.executeOnFiles(["./tests/fixtures/"]);
+            }, "All files matched by './tests/fixtures/' are ignored.");
         });
 
         // https://github.com/eslint/eslint/issues/3788
@@ -1081,7 +1078,7 @@ describe("CLIEngine", () => {
         });
 
         // https://github.com/eslint/eslint/issues/3812
-        it("should ignore all files when tests/fixtures/ is in ignore file", () => {
+        it("should ignore all files and throw an error when tests/fixtures/ is in ignore file", () => {
             engine = new CLIEngine({
                 ignorePath: getFixturePath("cli-engine/.eslintignore2"),
                 useEslintrc: false,
@@ -1090,19 +1087,19 @@ describe("CLIEngine", () => {
                 }
             });
 
-            const report = engine.executeOnFiles(["./tests/fixtures/cli-engine/"]);
-
-            assert.strictEqual(report.results.length, 0);
+            assert.throws(() => {
+                engine.executeOnFiles(["./tests/fixtures/cli-engine/"]);
+            }, "No files matching './tests/fixtures/cli-engine/' were found.");
         });
 
-        it("should return zero messages when all given files are ignored via ignore-pattern", () => {
+        it("should throw an error when all given files are ignored via ignore-pattern", () => {
             engine = new CLIEngine({
                 ignorePattern: "tests/fixtures/single-quoted.js"
             });
 
-            const report = engine.executeOnFiles(["tests/fixtures/*-quoted.js"]);
-
-            assert.strictEqual(report.results.length, 0);
+            assert.throws(() => {
+                engine.executeOnFiles(["tests/fixtures/*-quoted.js"]);
+            }, "All files matched by 'tests/fixtures/*-quoted.js' are ignored.");
         });
 
         it("should return a warning when an explicitly given file is ignored", () => {
@@ -1344,29 +1341,6 @@ describe("CLIEngine", () => {
             assert.strictEqual(report.results[0].messages.length, 0);
         });
 
-        it("should not fail if an ignored file cannot be resolved", () => {
-
-            const fakeFS = leche.fake(fs),
-                LocalCLIEngine = proxyquire("../../lib/cli-engine", {
-                    fs: fakeFS
-                });
-
-            fakeFS.realpathSync = function() {
-                throw new Error("this error should not happen");
-            };
-            fakeFS.existsSync = fs.existsSync;
-            fakeFS.unlinkSync = fs.unlinkSync;
-
-            engine = new LocalCLIEngine({
-                ignorePattern: "tests"
-            });
-
-            assert.doesNotThrow(() => {
-                engine.executeOnFiles(["tests/fixtures/file-not-found.js"]);
-            });
-
-        });
-
         describe("Fix Mode", () => {
 
             it("should return fixed text on multiple files when in fix mode", () => {
@@ -2600,6 +2574,45 @@ describe("CLIEngine", () => {
                 });
             });
         });
+
+        describe("Patterns which match no file should throw errors.", () => {
+            beforeEach(() => {
+                engine = new CLIEngine({
+                    cwd: getFixturePath("cli-engine"),
+                    useEslintrc: false
+                });
+            });
+
+            it("one file", () => {
+                assert.throws(() => {
+                    engine.executeOnFiles(["non-exist.js"]);
+                }, "No files matching 'non-exist.js' were found.");
+            });
+
+            it("should throw if the directory exists and is empty", () => {
+                assert.throws(() => {
+                    engine.executeOnFiles(["empty"]);
+                }, "No files matching 'empty' were found.");
+            });
+
+            it("one glob pattern", () => {
+                assert.throws(() => {
+                    engine.executeOnFiles(["non-exist/**/*.js"]);
+                }, "No files matching 'non-exist/**/*.js' were found.");
+            });
+
+            it("two files", () => {
+                assert.throws(() => {
+                    engine.executeOnFiles(["aaa.js", "bbb.js"]);
+                }, "No files matching 'aaa.js' were found.");
+            });
+
+            it("a mix of an existing file and a non-existing file", () => {
+                assert.throws(() => {
+                    engine.executeOnFiles(["console.js", "non-exist.js"]);
+                }, "No files matching 'non-exist.js' were found.");
+            });
+        });
     });
 
     describe("getConfigForFile", () => {
@@ -2976,9 +2989,10 @@ describe("CLIEngine", () => {
     describe("resolveFileGlobPatterns", () => {
 
         leche.withData([
-            [".", "**/*.js"],
-            ["./", "**/*.js"],
-            ["../", "../**/*.js"]
+            [".", ["**/*.js"]],
+            ["./", ["**/*.js"]],
+            ["../", ["../**/*.js"]],
+            ["", []]
         ], (input, expected) => {
 
             it(`should correctly resolve ${input} to ${expected}`, () => {
@@ -2986,7 +3000,7 @@ describe("CLIEngine", () => {
 
                 const result = engine.resolveFileGlobPatterns([input]);
 
-                assert.strictEqual(result[0], expected);
+                assert.deepStrictEqual(result, expected);
 
             });
         });
diff --git a/tests/lib/cli.js b/tests/lib/cli.js
index 04a966c81..2abf0d0ef 100644
--- a/tests/lib/cli.js
+++ b/tests/lib/cli.js
@@ -320,13 +320,13 @@ describe("cli", () => {
     });
 
     describe("when given a directory with eslint excluded files in the directory", () => {
-        it("should not process any files", () => {
+        it("should throw an error and not process any files", () => {
             const ignorePath = getFixturePath(".eslintignore");
             const filePath = getFixturePath(".");
-            const exit = cli.execute(`--ignore-path ${ignorePath} ${filePath}`);
 
-            assert.isTrue(log.info.notCalled);
-            assert.strictEqual(exit, 0);
+            assert.throws(() => {
+                cli.execute(`--ignore-path ${ignorePath} ${filePath}`);
+            }, `All files matched by '${filePath}' are ignored.`);
         });
     });
 
diff --git a/tests/lib/config.js b/tests/lib/config.js
index 1f9690339..6baae0e05 100644
--- a/tests/lib/config.js
+++ b/tests/lib/config.js
@@ -83,6 +83,14 @@ function assertConfigsEqual(actual, expected) {
     }
 }
 
+/**
+ * Wait for the next tick.
+ * @returns {Promise<void>} -
+ */
+function nextTick() {
+    return new Promise(resolve => process.nextTick(resolve));
+}
+
 //------------------------------------------------------------------------------
 // Tests
 //------------------------------------------------------------------------------
@@ -1086,7 +1094,6 @@ describe("Config", () => {
             });
         });
 
-
         describe("with overrides", () => {
 
             /**
@@ -1359,6 +1366,112 @@ describe("Config", () => {
                 assertConfigsEqual(actual, expected);
             });
         });
+
+        describe("deprecation warnings", () => {
+            let warning = null;
+
+            function onWarning(w) { // eslint-disable-line require-jsdoc
+
+                // Node.js 6.x does not have 'w.code' property.
+                if (!w.hasOwnProperty("code") || typeof w.code === "string" && w.code.startsWith("ESLINT_")) {
+                    warning = w;
+                }
+            }
+
+            beforeEach(() => {
+                warning = null;
+                process.on("warning", onWarning);
+            });
+            afterEach(() => {
+                process.removeListener("warning", onWarning);
+            });
+
+            it("should emit a deprecation warning if 'ecmaFeatures' is given.", () => Promise.resolve()
+                .then(() => {
+                    const cwd = path.resolve(__dirname, "../fixtures/config-file/ecma-features/");
+                    const config = new Config({ cwd }, linter);
+
+                    config.getConfig("test.js");
+
+                    // Wait for "warning" event.
+                    return nextTick();
+                })
+                .then(() => {
+                    assert.notStrictEqual(warning, null);
+                    assert.strictEqual(
+                        warning.message,
+                        `The 'ecmaFeatures' config file property is deprecated, and has no effect. (found in "tests${path.sep}fixtures${path.sep}config-file${path.sep}ecma-features${path.sep}.eslintrc.yml")`
+                    );
+                }));
+
+            it("should emit a deprecation warning if 'parserOptions.ecmaFeatures.experimentalObjectRestSpread' is given.", () => Promise.resolve()
+                .then(() => {
+                    const cwd = path.resolve(__dirname, "../fixtures/config-file/experimental-object-rest-spread/basic/");
+                    const config = new Config({ cwd }, linter);
+
+                    config.getConfig("test.js");
+
+                    // Wait for "warning" event.
+                    return nextTick();
+                })
+                .then(() => {
+                    assert.notStrictEqual(warning, null);
+                    assert.strictEqual(
+                        warning.message,
+                        `The 'parserOptions.ecmaFeatures.experimentalObjectRestSpread' option is deprecated. Use 'parserOptions.ecmaVersion' instead. (found in "tests${path.sep}fixtures${path.sep}config-file${path.sep}experimental-object-rest-spread${path.sep}basic${path.sep}.eslintrc.yml")`
+                    );
+                }));
+
+            it("should emit a deprecation warning if 'parserOptions.ecmaFeatures.experimentalObjectRestSpread' is given in a parent config.", () => Promise.resolve()
+                .then(() => {
+                    const cwd = path.resolve(__dirname, "../fixtures/config-file/experimental-object-rest-spread/subdir/");
+                    const config = new Config({ cwd }, linter);
+
+                    config.getConfig("lib/test.js");
+
+                    // Wait for "warning" event.
+                    return nextTick();
+                })
+                .then(() => {
+                    assert.notStrictEqual(warning, null);
+                    assert.strictEqual(
+                        warning.message,
+                        `The 'parserOptions.ecmaFeatures.experimentalObjectRestSpread' option is deprecated. Use 'parserOptions.ecmaVersion' instead. (found in "tests${path.sep}fixtures${path.sep}config-file${path.sep}experimental-object-rest-spread${path.sep}subdir${path.sep}.eslintrc.yml")`
+                    );
+                }));
+
+            it("should emit a deprecation warning if 'parserOptions.ecmaFeatures.experimentalObjectRestSpread' is given in a shareable config.", () => Promise.resolve()
+                .then(() => {
+                    const cwd = path.resolve(__dirname, "../fixtures/config-file/experimental-object-rest-spread/extends/");
+                    const config = new Config({ cwd }, linter);
+
+                    config.getConfig("test.js");
+
+                    // Wait for "warning" event.
+                    return nextTick();
+                })
+                .then(() => {
+                    assert.notStrictEqual(warning, null);
+                    assert.strictEqual(
+                        warning.message,
+                        `The 'parserOptions.ecmaFeatures.experimentalObjectRestSpread' option is deprecated. Use 'parserOptions.ecmaVersion' instead. (found in "tests${path.sep}fixtures${path.sep}config-file${path.sep}experimental-object-rest-spread${path.sep}extends${path.sep}common.yml")`
+                    );
+                }));
+
+            it("should NOT emit a deprecation warning even if 'parserOptions.ecmaFeatures.experimentalObjectRestSpread' is given, if parser is not espree.", () => Promise.resolve()
+                .then(() => {
+                    const cwd = path.resolve(__dirname, "../fixtures/config-file/experimental-object-rest-spread/another-parser/");
+                    const config = new Config({ cwd }, linter);
+
+                    config.getConfig("test.js");
+
+                    // Wait for "warning" event.
+                    return nextTick();
+                })
+                .then(() => {
+                    assert.strictEqual(warning, null);
+                }));
+        });
     });
 
     describe("Plugin Environments", () => {
diff --git a/tests/lib/config/config-file.js b/tests/lib/config/config-file.js
index 91c6508d4..287a7d67d 100644
--- a/tests/lib/config/config-file.js
+++ b/tests/lib/config/config-file.js
@@ -8,7 +8,8 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const assert = require("chai").assert,
+const Module = require("module"),
+    assert = require("chai").assert,
     leche = require("leche"),
     sinon = require("sinon"),
     path = require("path"),
@@ -127,6 +128,29 @@ function createStubModuleResolver(mapping) {
     };
 }
 
+/**
+ * Overrides the native module resolver to resolve with the given mappings.
+ * @param {Object<string,string>} mapping A mapping of module name to path.
+ * @returns {void}
+ * @private
+ */
+function overrideNativeResolve(mapping) {
+    let originalFindPath;
+
+    beforeEach(() => {
+        originalFindPath = Module._findPath; // eslint-disable-line no-underscore-dangle
+        Module._findPath = function(request, paths, isMain) { // eslint-disable-line no-underscore-dangle
+            if (mapping.hasOwnProperty(request)) {
+                return mapping[request];
+            }
+            return originalFindPath.call(this, request, paths, isMain);
+        };
+    });
+    afterEach(() => {
+        Module._findPath = originalFindPath; // eslint-disable-line no-underscore-dangle
+    });
+}
+
 //------------------------------------------------------------------------------
 // Tests
 //------------------------------------------------------------------------------
@@ -145,6 +169,10 @@ describe("ConfigFile", () => {
 
     describe("applyExtends()", () => {
 
+        overrideNativeResolve({
+            "eslint-plugin-test": getProjectModulePath("eslint-plugin-test")
+        });
+
         it("should apply extension 'foo' when specified from root directory config", () => {
 
             const resolvedPath = path.resolve(PROJECT_PATH, "./node_modules/eslint-config-foo/index.js");
@@ -864,6 +892,10 @@ describe("ConfigFile", () => {
 
         describe("Plugins", () => {
 
+            overrideNativeResolve({
+                "eslint-plugin-test": getProjectModulePath("eslint-plugin-test")
+            });
+
             it("should load information from a YML file and load plugins", () => {
 
                 const stubConfig = new Config({}, new Linter());
@@ -895,9 +927,6 @@ describe("ConfigFile", () => {
                 const resolvedPath = path.resolve(PROJECT_PATH, "./node_modules/eslint-plugin-test/index.js");
 
                 const configDeps = {
-                    "../util/module-resolver": createStubModuleResolver({
-                        "eslint-plugin-test": resolvedPath
-                    }),
                     "require-uncached"(filename) {
                         return configDeps[filename];
                     }
@@ -1000,6 +1029,9 @@ describe("ConfigFile", () => {
     describe("resolve()", () => {
 
         describe("Relative to CWD", () => {
+            overrideNativeResolve({
+                "eslint-plugin-foo": getProjectModulePath("eslint-plugin-foo")
+            });
 
             leche.withData([
                 [".eslintrc", path.resolve(".eslintrc")],
@@ -1035,6 +1067,10 @@ describe("ConfigFile", () => {
 
             const relativePath = path.resolve("./foo/bar");
 
+            overrideNativeResolve({
+                "@foo/eslint-plugin-bar": getProjectModulePath("@foo/eslint-plugin-bar")
+            });
+
             leche.withData([
                 [".eslintrc", path.resolve("./foo/bar", ".eslintrc"), relativePath],
                 ["eslint-config-foo", getRelativeModulePath("eslint-config-foo", relativePath), relativePath],
@@ -1042,7 +1078,7 @@ describe("ConfigFile", () => {
                 ["eslint-configfoo", getRelativeModulePath("eslint-config-eslint-configfoo", relativePath), relativePath],
                 ["@foo/eslint-config", getRelativeModulePath("@foo/eslint-config", relativePath), relativePath],
                 ["@foo/bar", getRelativeModulePath("@foo/eslint-config-bar", relativePath), relativePath],
-                ["plugin:@foo/bar/baz", getRelativeModulePath("@foo/eslint-plugin-bar", relativePath), relativePath]
+                ["plugin:@foo/bar/baz", getProjectModulePath("@foo/eslint-plugin-bar"), relativePath]
             ], (input, expected, relativeTo) => {
                 it(`should return ${expected} when passed ${input}`, () => {
 
@@ -1050,9 +1086,7 @@ describe("ConfigFile", () => {
                         "eslint-config-foo": getRelativeModulePath("eslint-config-foo", relativePath),
                         "eslint-config-eslint-configfoo": getRelativeModulePath("eslint-config-eslint-configfoo", relativePath),
                         "@foo/eslint-config": getRelativeModulePath("@foo/eslint-config", relativePath),
-                        "@foo/eslint-config-bar": getRelativeModulePath("@foo/eslint-config-bar", relativePath),
-                        "eslint-plugin-foo": getRelativeModulePath("eslint-plugin-foo", relativePath),
-                        "@foo/eslint-plugin-bar": getRelativeModulePath("@foo/eslint-plugin-bar", relativePath)
+                        "@foo/eslint-config-bar": getRelativeModulePath("@foo/eslint-config-bar", relativePath)
                     };
 
                     const StubbedConfigFile = proxyquire("../../../lib/config/config-file", {
diff --git a/tests/lib/config/config-initializer.js b/tests/lib/config/config-initializer.js
index ceeed0cb3..72c7d2e99 100644
--- a/tests/lib/config/config-initializer.js
+++ b/tests/lib/config/config-initializer.js
@@ -380,7 +380,7 @@ describe("configInitializer", () => {
                 process.chdir(fixtureDir);
                 assert.throws(() => {
                     config = init.processAnswers(answers);
-                }, "Automatic Configuration failed.  No files were able to be parsed.");
+                }, "No files matching 'not-a-real-filename' were found.");
             });
         });
     });
diff --git a/tests/lib/linter.js b/tests/lib/linter.js
index 53290c1ed..667e75e5b 100644
--- a/tests/lib/linter.js
+++ b/tests/lib/linter.js
@@ -3492,6 +3492,15 @@ describe("Linter", () => {
             linter.verify("x", { rules: { "foo-bar-baz": "error" } });
             assert(spy.calledOnce);
         });
+
+        it("should parse ES2018 code for backward compatibility if 'parserOptions.ecmaFeatures.experimentalObjectRestSpread' is given.", () => {
+            const messages = linter.verify(
+                "async function* f() { let {a, ...rest} = { a, ...obj }; }",
+                { parserOptions: { ecmaFeatures: { experimentalObjectRestSpread: true } } }
+            );
+
+            assert(messages.length === 0);
+        });
     });
 
     describe("Variables and references", () => {
diff --git a/tests/lib/rules/object-shorthand.js b/tests/lib/rules/object-shorthand.js
index 31abe8faa..c52f43af0 100644
--- a/tests/lib/rules/object-shorthand.js
+++ b/tests/lib/rules/object-shorthand.js
@@ -427,6 +427,16 @@ ruleTester.run("object-shorthand", rule, {
             output: "var x = {\n  *f() {\n    /* comment */\n    a(b);\n    }\n  }",
             errors: [METHOD_ERROR]
         },
+        {
+            code: "var x = {\n  f: /* comment */ function() {\n  }\n  }",
+            output: null,
+            errors: [METHOD_ERROR]
+        },
+        {
+            code: "var x = {\n f /* comment */: function() {\n  }\n  }",
+            output: null,
+            errors: [METHOD_ERROR]
+        },
         {
             code: "var x = {y: function() {}}",
             output: "var x = {y() {}}",
diff --git a/tests/lib/rules/valid-jsdoc.js b/tests/lib/rules/valid-jsdoc.js
index d6e0219c5..7304192be 100644
--- a/tests/lib/rules/valid-jsdoc.js
+++ b/tests/lib/rules/valid-jsdoc.js
@@ -267,6 +267,32 @@ ruleTester.run("valid-jsdoc", rule, {
             options: [{ requireReturn: false }]
         },
 
+        // async function
+        {
+            code:
+              "/**\n" +
+              " * An async function. Options requires return.\n" +
+              " * @returns {Promise} that is empty\n" +
+              " */\n" +
+              "async function a() {}",
+            options: [{ requireReturn: true }],
+            parserOptions: {
+                ecmaVersion: 2017
+            }
+        },
+        {
+            code:
+              "/**\n" +
+              " * An async function. Options do not require return.\n" +
+              " * @returns {Promise} that is empty\n" +
+              " */\n" +
+              "async function a() {}",
+            options: [{ requireReturn: false }],
+            parserOptions: {
+                ecmaVersion: 2017
+            }
+        },
+
         // type validations
         {
             code:
diff --git a/tests/lib/util/glob-util.js b/tests/lib/util/glob-util.js
index 47c601d26..516b1bc83 100644
--- a/tests/lib/util/glob-util.js
+++ b/tests/lib/util/glob-util.js
@@ -140,17 +140,6 @@ describe("globUtil", () => {
 
             assert.deepStrictEqual(result, ["one-js-file/example.js"]);
         });
-
-        it("should ignore empty patterns", () => {
-            const patterns = [""];
-            const opts = {
-                cwd: getFixturePath()
-            };
-            const result = globUtil.resolveFileGlobPatterns(patterns, opts);
-
-            assert.deepStrictEqual(result, []);
-        });
-
     });
 
     describe("listFilesToProcess()", () => {
@@ -204,13 +193,14 @@ describe("globUtil", () => {
             ]);
         });
 
-        it("should not return hidden files for standard glob patterns", () => {
+        it("should ignore hidden files for standard glob patterns", () => {
             const patterns = [getFixturePath("glob-util", "hidden", "**/*.js")];
-            const result = globUtil.listFilesToProcess(patterns, {
-                cwd: getFixturePath()
-            });
 
-            assert.strictEqual(result.length, 0);
+            assert.throws(() => {
+                globUtil.listFilesToProcess(patterns, {
+                    cwd: getFixturePath()
+                });
+            }, `All files matched by '${patterns[0]}' are ignored.`);
         });
 
         it("should return hidden files if included in glob pattern", () => {
@@ -227,14 +217,15 @@ describe("globUtil", () => {
             ]);
         });
 
-        it("should silently ignore default ignored files if not passed explicitly", () => {
+        it("should ignore default ignored files if not passed explicitly", () => {
             const directory = getFixturePath("glob-util", "hidden");
             const patterns = [directory];
-            const result = globUtil.listFilesToProcess(patterns, {
-                cwd: getFixturePath()
-            });
 
-            assert.strictEqual(result.length, 0);
+            assert.throws(() => {
+                globUtil.listFilesToProcess(patterns, {
+                    cwd: getFixturePath()
+                });
+            }, `All files matched by '${directory}' are ignored.`);
         });
 
         it("should ignore and warn for default ignored files when passed explicitly", () => {
@@ -248,15 +239,16 @@ describe("globUtil", () => {
             assert.deepStrictEqual(result[0], { filename, ignored: true });
         });
 
-        it("should silently ignore default ignored files if not passed explicitly even if ignore is false", () => {
+        it("should ignore default ignored files if not passed explicitly even if ignore is false", () => {
             const directory = getFixturePath("glob-util", "hidden");
             const patterns = [directory];
-            const result = globUtil.listFilesToProcess(patterns, {
-                cwd: getFixturePath(),
-                ignore: false
-            });
 
-            assert.strictEqual(result.length, 0);
+            assert.throws(() => {
+                globUtil.listFilesToProcess(patterns, {
+                    cwd: getFixturePath(),
+                    ignore: false
+                });
+            }, `All files matched by '${directory}' are ignored.`);
         });
 
         it("should not ignore default ignored files when passed explicitly if ignore is false", () => {
@@ -271,20 +263,46 @@ describe("globUtil", () => {
             assert.deepStrictEqual(result[0], { filename, ignored: false });
         });
 
-        it("should not return a file which does not exist", () => {
-            const patterns = ["tests/fixtures/glob-util/hidden/bar.js"];
-            const result = globUtil.listFilesToProcess(patterns);
+        it("should throw an error for a file which does not exist", () => {
+            const filename = getFixturePath("glob-util", "hidden", "bar.js");
+            const patterns = [filename];
+
+            assert.throws(() => {
+                globUtil.listFilesToProcess(patterns, {
+                    cwd: getFixturePath(),
+                    allowMissingGlobs: true
+                });
+            }, `No files matching '${filename}' were found.`);
+        });
+
+        it("should throw if a folder that does not have any applicable files is linted", () => {
+            const filename = getFixturePath("glob-util", "empty");
+            const patterns = [filename];
 
-            assert.strictEqual(result.length, 0);
+            assert.throws(() => {
+                globUtil.listFilesToProcess(patterns, {
+                    cwd: getFixturePath()
+                });
+            }, `No files matching '${filename}' were found.`);
         });
 
-        it("should not return an ignored file", () => {
+        it("should throw if only ignored files match a glob", () => {
+            const pattern = getFixturePath("glob-util", "ignored");
+            const options = { ignore: true, ignorePath: getFixturePath("glob-util", "ignored", ".eslintignore") };
+
+            assert.throws(() => {
+                globUtil.listFilesToProcess([pattern], options);
+            }, `All files matched by '${pattern}' are ignored.`);
+        });
+
+        it("should throw an error if no files match a glob", () => {
 
             // Relying here on the .eslintignore from the repo root
             const patterns = ["tests/fixtures/glob-util/ignored/**/*.js"];
-            const result = globUtil.listFilesToProcess(patterns);
 
-            assert.strictEqual(result.length, 0);
+            assert.throws(() => {
+                globUtil.listFilesToProcess(patterns);
+            }, `No files matching '${patterns[0]}' were found.`);
         });
 
         it("should return an ignored file, if ignore option is turned off", () => {
@@ -295,20 +313,22 @@ describe("globUtil", () => {
             assert.strictEqual(result.length, 1);
         });
 
-        it("should not return a file from a glob if it matches a pattern in an ignore file", () => {
+        it("should ignore a file from a glob if it matches a pattern in an ignore file", () => {
             const options = { ignore: true, ignorePath: getFixturePath("glob-util", "ignored", ".eslintignore") };
             const patterns = [getFixturePath("glob-util", "ignored", "**/*.js")];
-            const result = globUtil.listFilesToProcess(patterns, options);
 
-            assert.strictEqual(result.length, 0);
+            assert.throws(() => {
+                globUtil.listFilesToProcess(patterns, options);
+            }, `All files matched by '${patterns[0]}' are ignored.`);
         });
 
-        it("should not return a file from a glob if matching a specified ignore pattern", () => {
+        it("should ignore a file from a glob if matching a specified ignore pattern", () => {
             const options = { ignore: true, ignorePattern: "foo.js", cwd: getFixturePath() };
             const patterns = [getFixturePath("glob-util", "ignored", "**/*.js")];
-            const result = globUtil.listFilesToProcess(patterns, options);
 
-            assert.strictEqual(result.length, 0);
+            assert.throws(() => {
+                globUtil.listFilesToProcess(patterns, options);
+            }, `All files matched by '${patterns[0]}' are ignored.`);
         });
 
         it("should return a file only once if listed in more than 1 pattern", () => {
diff --git a/tests/lib/util/source-code-util.js b/tests/lib/util/source-code-util.js
index 374443321..1a406e5d3 100644
--- a/tests/lib/util/source-code-util.js
+++ b/tests/lib/util/source-code-util.js
@@ -155,11 +155,12 @@ describe("SourceCodeUtil", () => {
             assert.property(sourceCode, barFilename);
         });
 
-        it("should should not include non-existent filesnames in results", () => {
+        it("should should not include non-existent filenames in results", () => {
             const filename = getFixturePath("missing.js");
-            const sourceCode = getSourceCodeOfFiles(filename, { cwd: fixtureDir });
 
-            assert.notProperty(sourceCode, filename);
+            assert.throws(() => {
+                getSourceCodeOfFiles(filename, { cwd: fixtureDir });
+            }, `No files matching '${filename}' were found.`);
         });
 
         it("should throw for files with parsing errors", () => {
@@ -248,9 +249,8 @@ describe("SourceCodeUtil", () => {
             const firstFn = getFixturePath("foo.js");
             const secondFn = getFixturePath("bar.js");
             const thirdFn = getFixturePath("nested/foo.js");
-            const missingFn = getFixturePath("missing.js");
 
-            getSourceCodeOfFiles([firstFn, secondFn, thirdFn, missingFn], { cwd: fixtureDir }, callback);
+            getSourceCodeOfFiles([firstFn, secondFn, thirdFn], { cwd: fixtureDir }, callback);
             assert(callback.calledWith(3));
         });