Repository: eslint/eslint
Pull request #9944 (2018-02-05 14:05:09)

Chore: Apply memoization to config creation within glob utils
<!--
    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:

<!--
    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)**

I attempted a brief review of `eslint` with performance in mind and I found (just) a few quick wins.

Running the repo's `lint` task with `--debug` I first noticed that the ignore file processing occurred multiple times in a row without significant changes.

```
2018-02-05T02:52:54.126Z eslint:cli Running on files
2018-02-05T02:52:54.131Z eslint:glob-util Creating list of files to process.
2018-02-05T02:52:54.132Z eslint:ignored-paths Looking for ignore file in ~/Projects/eslint
2018-02-05T02:52:54.132Z eslint:ignored-paths Loaded ignore file /Users/kjacobse/Projects/eslint/.eslintignore
2018-02-05T02:52:54.132Z eslint:ignored-paths Adding ~/Projects/eslint/.eslintignore
2018-02-05T02:52:54.213Z eslint:ignored-paths Looking for ignore file in ~/Projects/eslint
2018-02-05T02:52:54.213Z eslint:ignored-paths Loaded ignore file /Users/kjacobse/Projects/eslint/.eslintignore
2018-02-05T02:52:54.213Z eslint:ignored-paths Adding ~/Projects/eslint/.eslintignore
2018-02-05T02:52:54.215Z eslint:ignored-paths Looking for ignore file in~/Projects/eslint
2018-02-05T02:52:54.215Z eslint:ignored-paths Loaded ignore file /Users/kjacobse/Projects/eslint/.eslintignore
2018-02-05T02:52:54.215Z eslint:ignored-paths Adding ~/Projects/eslint/.eslintignore
2018-02-05T02:52:54.216Z eslint:ignored-paths Looking for ignore file in ~/Projects/eslint
2018-02-05T02:52:54.216Z eslint:ignored-paths Loaded ignore file /Users/kjacobse/Projects/eslint/.eslintignore
2018-02-05T02:52:54.216Z eslint:ignored-paths Adding ~/Projects/eslint/.eslintignore
2018-02-05T02:52:54.219Z eslint:cli-engine Processing ~/Projects/eslint/lib/api.js
2018-02-05T02:52:54.219Z eslint:cli-engine Linting ~/Projects/eslint/lib/api.js
2018-02-05T02:52:54.219Z eslint:config Constructing config file hierarchy for ~/Projects/eslint/lib
...
```

In this branch, the above ignored-paths steps only occur once.

Anecdotally, I have been seeing pretty consistent gains in the `perf` execution, but even bumping the runs up a lot, it's simply too noisy to post and stand behind. I can attempt some more work on this if desired.

That all said, what I have done is prevent a new object creation (due to its cost and loss of referential equality) when it's unnecessary.

Then once that has been done, since I noticed these executions are more likely to be similar than different, I included two small, memoized functions to help create this object, and get a new instance of the `IgnoredPaths` class.

**Is there anything you'd like reviewers to focus on?**
I need help testing my assumptions:
* I am assuming that downstream consumers do not need unique copies of `IgnoredPaths` class. I feel pretty good about the immediate consumer `addFile`, but I don't necessarily have enough context for the rest.
* I am also assuming that this eslint runtime has a finite shelflife -- if not this memoization in the module scope is a classic memory leak (though there also may be finite enough inputs that it also may not matter), but nonetheless, worth the discussion.



jsf-clabot: [![CLA assistant check](https://cla.js.foundation/pull/badge/not_signed)](https://cla.js.foundation/eslint/eslint?pullRequest=9944) <br/>Thank you for your submission, we really appreciate it. Like many open source projects, we ask that you sign our [Contributor License Agreement](https://cla.js.foundation/eslint/eslint?pullRequest=9944) before we can accept your contribution.<br/>
brokentone: @platinumazure changes made! Left the commit out for clarity for now, will rebase them in later.
not-an-aardvark: Thanks for the PR! To clarify, does this just memoize the creation of the `IgnoredPaths` object, and not the results of checking the filesystem for ignored paths? (I wouldn't want to do the latter because the result could change if someone adds a file and runs ESLint again in the same process, e.g. as part of an editor integration.)
brokentone: @not-an-aardvark that is correct.

To your point, I'm not sure how some of the editor integrations happen, but if they're long-running, and if it's possible that this options object gets mutated upstream, we might provide an old response due to a false positive on referential equality. I'm imagining this is not the case though.

Patch:
diff --git a/.github/ISSUE_TEMPLATE/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md
similarity index 100%
rename from .github/ISSUE_TEMPLATE/ISSUE_TEMPLATE.md
rename to .github/ISSUE_TEMPLATE.md
diff --git a/docs/developer-guide/nodejs-api.md b/docs/developer-guide/nodejs-api.md
index c774666e0..4988f2696 100644
--- a/docs/developer-guide/nodejs-api.md
+++ b/docs/developer-guide/nodejs-api.md
@@ -496,7 +496,7 @@ If the operation ends with a parsing error, you will get a single message for th
             warningCount: 0,
             fixableErrorCount: 0,
             fixableWarningCount: 0,
-            source: "fucntion foo() {}"
+            source: "function foo() {}"
         }
     ],
     errorCount: 1,
diff --git a/docs/rules/key-spacing.md b/docs/rules/key-spacing.md
index 2c4afae8c..6e2b90541 100644
--- a/docs/rules/key-spacing.md
+++ b/docs/rules/key-spacing.md
@@ -10,14 +10,18 @@ This rule enforces consistent spacing between keys and values in object literal
 
 This rule has an object option:
 
-* `"beforeColon": false` (default) disallows spaces between the key and the colon in object literals.
-* `"beforeColon": true` requires at least one space between the key and the colon in object literals.
-* `"afterColon": true` (default) requires at least one space between the colon and the value in object literals.
-* `"afterColon": false` disallows spaces between the colon and the value in object literals.
-* `"mode": "strict"` (default) enforces exactly one space before or after colons in object literals.
-* `"mode": "minimum"` enforces one or more spaces before or after colons in object literals.
-* `"align": "value"` enforces horizontal alignment of values in object literals.
-* `"align": "colon"` enforces horizontal alignment of both colons and values in object literals.
+* `"beforeColon": false (default) | true`
+    * `false`: disallows spaces between the key and the colon in object literals.
+    * `true`: requires at least one space between the key and the colon in object literals.
+* `"afterColon": true (default) | false`
+    * `true`: requires at least one space between the colon and the value in object literals.
+    * `false`: disallows spaces between the colon and the value in object literals.
+* `"mode": "strict" (default) | "miniumum"`
+    * `"strict"`: enforces exactly one space before or after colons in object literals.
+    * `"minimum"`: enforces one or more spaces before or after colons in object literals.
+* `"align": "value" | "colon"`
+    * `"value"`: enforces horizontal alignment of values in object literals.
+    * `"colon"` enforces horizontal alignment of both colons and values in object literals.
 * `"align"` with an object value allows for fine-grained spacing when values are being aligned in object literals.
 * `"singleLine"` specifies a spacing style for single-line object literals.
 * `"multiLine"` specifies a spacing style for multi-line object literals.
diff --git a/docs/rules/max-len.md b/docs/rules/max-len.md
index 71339f01c..7aa755a34 100644
--- a/docs/rules/max-len.md
+++ b/docs/rules/max-len.md
@@ -147,7 +147,7 @@ var longRegExpLiteral = /this is a really really really really really long regul
 Examples of **correct** code for this rule with the `ignorePattern` option:
 
 ```js
-/*eslint max-len: ["error", { "ignorePattern": "^\\s*var\\s.+=\\s*require\\s*\(" }]*/
+/*eslint max-len: ["error", { "ignorePattern": "^\\s*var\\s.+=\\s*require\\s*\\(" }]*/
 
 var dep = require('really/really/really/really/really/really/really/really/long/module');
 ```
diff --git a/docs/rules/no-mixed-operators.md b/docs/rules/no-mixed-operators.md
index 1746c5ed6..3c0bb2fab 100644
--- a/docs/rules/no-mixed-operators.md
+++ b/docs/rules/no-mixed-operators.md
@@ -138,10 +138,19 @@ Examples of **incorrect** code for this rule with `{"allowSamePrecedence": false
 var foo = a + b - c;
 ```
 
+Examples of **correct** code for this rule with `{"allowSamePrecedence": false}` option:
+
+```js
+/*eslint no-mixed-operators: ["error", {"allowSamePrecedence": false}]*/
+
+// + and - have the same precedence.
+var foo = (a + b) - c;
+```
+
 ## When Not To Use It
 
 If you don't want to be notified about mixed operators, then it's safe to disable this rule.
 
 ## Related Rules
 
-* [no-extra-parens](no-extra-parens.md)
\ No newline at end of file
+* [no-extra-parens](no-extra-parens.md)
diff --git a/docs/rules/object-curly-newline.md b/docs/rules/object-curly-newline.md
index a4907046f..61c0e6862 100644
--- a/docs/rules/object-curly-newline.md
+++ b/docs/rules/object-curly-newline.md
@@ -19,19 +19,23 @@ Or an object option:
 * `"minProperties"` requires line breaks if the number of properties is at least the given integer. By default, an error will also be reported if an object contains linebreaks and has fewer properties than the given integer. However, the second behavior is disabled if the `consistent` option is set to `true`
 * `"consistent": true` requires that either both curly braces, or neither, directly enclose newlines. Note that enabling this option will also change the behavior of the `minProperties` option. (See `minProperties` above for more information)
 
-You can specify different options for object literals and destructuring assignments:
+You can specify different options for object literals, destructuring assignments, and named imports and exports:
 
 ```json
 {
     "object-curly-newline": ["error", {
         "ObjectExpression": "always",
-        "ObjectPattern": { "multiline": true }
+        "ObjectPattern": { "multiline": true },
+        "ImportDeclaration": "never",
+        "ExportDeclaration": { "multiline": true, "minProperties": 3 }
     }]
 }
 ```
 
 * `"ObjectExpression"` configuration for object literals
 * `"ObjectPattern"` configuration for object patterns of destructuring assignments
+* `"ImportDeclaration"` configuration for named imports
+* `"ExportDeclaration"` configuration for named exports
 
 ### always
 
@@ -463,6 +467,48 @@ let {k = function() {
 }} = obj;
 ```
 
+### ImportDeclaration and ExportDeclaration
+
+Examples of **incorrect** code for this rule with the `{ "ImportDeclaration": "always", "ExportDeclaration": "never" }` options:
+
+```js
+/*eslint object-curly-newline: ["error", { "ImportDeclaration": "always", "ExportDeclaration": "never" }]*/
+/*eslint-env es6*/
+
+import {foo, bar} from 'foo-bar';
+import {foo as f, bar} from 'foo-bar';
+import {foo,
+    bar} from 'foo-bar';
+
+export {
+   foo,
+   bar
+};
+export {
+   foo as f,
+   bar
+} from 'foo-bar';
+```
+
+Examples of **correct** code for this rule with the `{ "ImportDeclaration": "always", "ExportDeclaration": "never" }` options:
+
+```js
+/*eslint object-curly-newline: ["error", { "ImportDeclaration": "always", "ExportDeclaration": "never" }]*/
+/*eslint-env es6*/
+
+import {
+    foo,
+    bar
+} from 'foo-bar';
+import {
+    foo as f,
+    bar
+} from 'foo-bar';
+
+export { foo, bar } from 'foo-bar';
+export { foo as f, bar } from 'foo-bar';
+```
+
 ## Compatibility
 
 * **JSCS**: [requirePaddingNewLinesInObjects](http://jscs.info/rule/requirePaddingNewLinesInObjects) and [disallowPaddingNewLinesInObjects](http://jscs.info/rule/disallowPaddingNewLinesInObjects)
diff --git a/docs/rules/prefer-destructuring.md b/docs/rules/prefer-destructuring.md
index e6c2b94bc..8525dc2d0 100644
--- a/docs/rules/prefer-destructuring.md
+++ b/docs/rules/prefer-destructuring.md
@@ -40,7 +40,7 @@ var { foo } = object;
 var foo = object.bar;
 
 let foo;
-({ foo } = object.bar);
+({ foo } = object);
 ```
 
 Examples of **incorrect** code when `enforceForRenamedProperties` is enabled:
diff --git a/docs/rules/valid-typeof.md b/docs/rules/valid-typeof.md
index 2ce02b490..60539eecb 100644
--- a/docs/rules/valid-typeof.md
+++ b/docs/rules/valid-typeof.md
@@ -20,7 +20,7 @@ Examples of **incorrect** code for this rule:
 typeof foo === "strnig"
 typeof foo == "undefimed"
 typeof bar != "nunber"
-typeof bar !== "fucntion"
+typeof bar !== "function"
 ```
 
 Examples of **correct** code for this rule:
diff --git a/docs/user-guide/configuring.md b/docs/user-guide/configuring.md
index 098fcdf43..5d4f93d55 100644
--- a/docs/user-guide/configuring.md
+++ b/docs/user-guide/configuring.md
@@ -394,13 +394,18 @@ You can also disable or enable specific rules for an entire file:
 alert('foo');
 ```
 
-To disable all rules on a specific line, use a line comment in one of the following formats:
+To disable all rules on a specific line, use a line or block comment in one of the following formats:
 
 ```js
 alert('foo'); // eslint-disable-line
 
 // eslint-disable-next-line
 alert('foo');
+
+/* eslint-disable-next-line */
+alert('foo');
+
+alert('foo'); /* eslint-disable-line */
 ```
 
 To disable a specific rule on a specific line:
@@ -410,6 +415,11 @@ alert('foo'); // eslint-disable-line no-alert
 
 // eslint-disable-next-line no-alert
 alert('foo');
+
+alert('foo'); /* eslint-disable-line no-alert */
+
+/* eslint-disable-next-line no-alert */
+alert('foo');
 ```
 
 To disable multiple rules on a specific line:
@@ -419,12 +429,18 @@ alert('foo'); // eslint-disable-line no-alert, quotes, semi
 
 // eslint-disable-next-line no-alert, quotes, semi
 alert('foo');
+
+alert('foo'); /* eslint-disable-line no-alert, quotes, semi */
+
+/* eslint-disable-next-line no-alert, quotes, semi */
+alert('foo');
 ```
 
 All of the above methods also work for plugin rules. For example, to disable `eslint-plugin-example`'s `rule-name` rule, combine the plugin's name (`example`) and the rule's name (`rule-name`) into `example/rule-name`:
 
 ```js
 foo(); // eslint-disable-line example/rule-name
+foo(); /* eslint-disable-line example/rule-name */
 ```
 
 **Note:** Comments that disable warnings for a portion of a file tell ESLint not to report rule violations for the disabled code. ESLint still parses the entire file, however, so disabled code still needs to be syntactically valid JavaScript.
diff --git a/lib/linter.js b/lib/linter.js
index d71a79a7c..8e95c3a71 100755
--- a/lib/linter.js
+++ b/lib/linter.js
@@ -307,7 +307,6 @@ function modifyConfigsFromComments(filename, ast, config, ruleMapper) {
 
         if (match) {
             value = value.slice(match.index + match[1].length);
-
             if (comment.type === "Block") {
                 switch (match[1]) {
                     case "exported":
@@ -323,6 +322,18 @@ function modifyConfigsFromComments(filename, ast, config, ruleMapper) {
                         [].push.apply(disableDirectives, createDisableDirectives("disable", comment.loc.start, value));
                         break;
 
+                    case "eslint-disable-line":
+                        if (comment.loc.start.line === comment.loc.end.line) {
+                            [].push.apply(disableDirectives, createDisableDirectives("disable-line", comment.loc.start, value));
+                        }
+                        break;
+
+                    case "eslint-disable-next-line":
+                        if (comment.loc.start.line === comment.loc.end.line) {
+                            [].push.apply(disableDirectives, createDisableDirectives("disable-next-line", comment.loc.start, value));
+                        }
+                        break;
+
                     case "eslint-enable":
                         [].push.apply(disableDirectives, createDisableDirectives("enable", comment.loc.start, value));
                         break;
diff --git a/lib/rules/indent.js b/lib/rules/indent.js
index 79a0f25ca..acc524630 100644
--- a/lib/rules/indent.js
+++ b/lib/rules/indent.js
@@ -1043,7 +1043,6 @@ module.exports = {
                 offsets.ignoreToken(operator);
                 offsets.ignoreToken(tokenAfterOperator);
                 offsets.setDesiredOffset(tokenAfterOperator, operator, 0);
-                offsets.setDesiredOffsets([tokenAfterOperator.range[1], node.range[1]], tokenAfterOperator, 1);
             },
 
             "BlockStatement, ClassBody"(node) {
diff --git a/lib/rules/key-spacing.js b/lib/rules/key-spacing.js
index 1ae4990a5..b1208e19e 100644
--- a/lib/rules/key-spacing.js
+++ b/lib/rules/key-spacing.js
@@ -360,9 +360,10 @@ module.exports = {
          */
         function isKeyValueProperty(property) {
             return !(
-                (property.method ||
+                property.method ||
                 property.shorthand ||
-                property.kind !== "init" || property.type !== "Property") // Could be "ExperimentalSpreadProperty" or "SpreadProperty"
+                property.kind !== "init" ||
+                property.type !== "Property" // Could be "ExperimentalSpreadProperty" or "SpreadElement"
             );
         }
 
diff --git a/lib/rules/keyword-spacing.js b/lib/rules/keyword-spacing.js
index d0dd64025..89b973325 100644
--- a/lib/rules/keyword-spacing.js
+++ b/lib/rules/keyword-spacing.js
@@ -436,7 +436,12 @@ module.exports = {
          * @returns {void}
          */
         function checkSpacingForForOfStatement(node) {
-            checkSpacingAroundFirstToken(node);
+            if (node.await) {
+                checkSpacingBefore(sourceCode.getFirstToken(node, 0));
+                checkSpacingAfter(sourceCode.getFirstToken(node, 1));
+            } else {
+                checkSpacingAroundFirstToken(node);
+            }
             checkSpacingAround(sourceCode.getTokenBefore(node.right, astUtils.isNotOpeningParenToken));
         }
 
diff --git a/lib/rules/no-await-in-loop.js b/lib/rules/no-await-in-loop.js
index 7a9427e6a..d0a2a5893 100644
--- a/lib/rules/no-await-in-loop.js
+++ b/lib/rules/no-await-in-loop.js
@@ -4,24 +4,54 @@
  */
 "use strict";
 
-// Node types which are considered loops.
-const loopTypes = new Set([
-    "ForStatement",
-    "ForOfStatement",
-    "ForInStatement",
-    "WhileStatement",
-    "DoWhileStatement"
-]);
+/**
+ * Check whether it should stop traversing ancestors at the given node.
+ * @param {ASTNode} node A node to check.
+ * @returns {boolean} `true` if it should stop traversing.
+ */
+function isBoundary(node) {
+    const t = node.type;
+
+    return (
+        t === "FunctionDeclaration" ||
+        t === "FunctionExpression" ||
+        t === "ArrowFunctionExpression" ||
 
-/*
- * Node types at which we should stop looking for loops. For example, it is fine to declare an async
- * function within a loop, and use await inside of that.
+        /*
+         * Don't report the await expressions on for-await-of loop since it's
+         * asynchronous iteration intentionally.
+         */
+        (t === "ForOfStatement" && node.await === true)
+    );
+}
+
+/**
+ * Check whether the given node is in loop.
+ * @param {ASTNode} node A node to check.
+ * @param {ASTNode} parent A parent node to check.
+ * @returns {boolean} `true` if the node is in loop.
  */
-const boundaryTypes = new Set([
-    "FunctionDeclaration",
-    "FunctionExpression",
-    "ArrowFunctionExpression"
-]);
+function isLooped(node, parent) {
+    switch (parent.type) {
+        case "ForStatement":
+            return (
+                node === parent.test ||
+                node === parent.update ||
+                node === parent.body
+            );
+
+        case "ForOfStatement":
+        case "ForInStatement":
+            return node === parent.body;
+
+        case "WhileStatement":
+        case "DoWhileStatement":
+            return node === parent.test || node === parent.body;
+
+        default:
+            return false;
+    }
+}
 
 module.exports = {
     meta: {
@@ -37,51 +67,36 @@ module.exports = {
         }
     },
     create(context) {
-        return {
-            AwaitExpression(node) {
-                const ancestors = context.getAncestors();
-
-                // Reverse so that we can traverse from the deepest node upwards.
-                ancestors.reverse();
-
-                /*
-                 * Create a set of all the ancestors plus this node so that we can check
-                 * if this use of await appears in the body of the loop as opposed to
-                 * the right-hand side of a for...of, for example.
-                 */
-                const ancestorSet = new Set(ancestors).add(node);
-
-                for (let i = 0; i < ancestors.length; i++) {
-                    const ancestor = ancestors[i];
 
-                    if (boundaryTypes.has(ancestor.type)) {
+        /**
+         * Validate an await expression.
+         * @param {ASTNode} awaitNode An AwaitExpression or ForOfStatement node to validate.
+         * @returns {void}
+         */
+        function validate(awaitNode) {
+            if (awaitNode.type === "ForOfStatement" && !awaitNode.await) {
+                return;
+            }
 
-                        /*
-                         * Short-circuit out if we encounter a boundary type. Loops above
-                         * this do not matter.
-                         */
-                        return;
-                    }
-                    if (loopTypes.has(ancestor.type)) {
+            let node = awaitNode;
+            let parent = node.parent;
 
-                        /*
-                         * Only report if we are actually in the body or another part that gets executed on
-                         * every iteration.
-                         */
-                        if (
-                            ancestorSet.has(ancestor.body) ||
-                            ancestorSet.has(ancestor.test) ||
-                            ancestorSet.has(ancestor.update)
-                        ) {
-                            context.report({
-                                node,
-                                messageId: "unexpectedAwait"
-                            });
-                            return;
-                        }
-                    }
+            while (parent && !isBoundary(parent)) {
+                if (isLooped(node, parent)) {
+                    context.report({
+                        node,
+                        messageId: "unexpectedAwait"
+                    });
+                    return;
                 }
+                node = parent;
+                parent = parent.parent;
             }
+        }
+
+        return {
+            AwaitExpression: validate,
+            ForOfStatement: validate
         };
     }
 };
diff --git a/lib/rules/no-self-assign.js b/lib/rules/no-self-assign.js
index 301404200..8091d7d2e 100644
--- a/lib/rules/no-self-assign.js
+++ b/lib/rules/no-self-assign.js
@@ -121,7 +121,9 @@ function eachSelfAssignment(left, right, props, report) {
         let startJ = 0;
 
         for (let i = right.properties.length - 1; i >= 0; --i) {
-            if (right.properties[i].type === "ExperimentalSpreadProperty") {
+            const propType = right.properties[i].type;
+
+            if (propType === "SpreadElement" || propType === "ExperimentalSpreadProperty") {
                 startJ = i + 1;
                 break;
             }
diff --git a/lib/rules/no-unused-vars.js b/lib/rules/no-unused-vars.js
index 1d0cef856..6ba573498 100644
--- a/lib/rules/no-unused-vars.js
+++ b/lib/rules/no-unused-vars.js
@@ -65,7 +65,7 @@ module.exports = {
     create(context) {
         const sourceCode = context.getSourceCode();
 
-        const REST_PROPERTY_TYPE = /^(?:Experimental)?RestProperty$/;
+        const REST_PROPERTY_TYPE = /^(?:RestElement|(?:Experimental)?RestProperty)$/;
 
         const config = {
             vars: "all",
diff --git a/lib/rules/object-curly-newline.js b/lib/rules/object-curly-newline.js
index 91b2ca6c9..14b5d06a7 100644
--- a/lib/rules/object-curly-newline.js
+++ b/lib/rules/object-curly-newline.js
@@ -10,6 +10,7 @@
 //------------------------------------------------------------------------------
 
 const astUtils = require("../ast-utils");
+const lodash = require("lodash");
 
 //------------------------------------------------------------------------------
 // Helpers
@@ -73,19 +74,57 @@ function normalizeOptionValue(value) {
  * Normalizes a given option value.
  *
  * @param {string|Object|undefined} options - An option value to parse.
- * @returns {{ObjectExpression: {multiline: boolean, minProperties: number}, ObjectPattern: {multiline: boolean, minProperties: number}}} Normalized option object.
+ * @returns {{
+ *   ObjectExpression: {multiline: boolean, minProperties: number, consistent: boolean},
+ *   ObjectPattern: {multiline: boolean, minProperties: number, consistent: boolean},
+ *   ImportDeclaration: {multiline: boolean, minProperties: number, consistent: boolean},
+ *   ExportNamedDeclaration : {multiline: boolean, minProperties: number, consistent: boolean}
+ * }} Normalized option object.
  */
 function normalizeOptions(options) {
-    if (options && (options.ObjectExpression || options.ObjectPattern)) {
+    const isNodeSpecificOption = lodash.overSome([lodash.isPlainObject, lodash.isString]);
+
+    if (lodash.isPlainObject(options) && lodash.some(options, isNodeSpecificOption)) {
         return {
             ObjectExpression: normalizeOptionValue(options.ObjectExpression),
-            ObjectPattern: normalizeOptionValue(options.ObjectPattern)
+            ObjectPattern: normalizeOptionValue(options.ObjectPattern),
+            ImportDeclaration: normalizeOptionValue(options.ImportDeclaration),
+            ExportNamedDeclaration: normalizeOptionValue(options.ExportDeclaration)
         };
     }
 
     const value = normalizeOptionValue(options);
 
-    return { ObjectExpression: value, ObjectPattern: value };
+    return { ObjectExpression: value, ObjectPattern: value, ImportDeclaration: value, ExportNamedDeclaration: value };
+}
+
+/**
+ * Determines if ObjectExpression, ObjectPattern, ImportDeclaration or ExportNamedDeclaration
+ * node needs to be checked for missing line breaks
+ *
+ * @param {ASTNode} node - Node under inspection
+ * @param {Object} options - option specific to node type
+ * @param {Token} first - First object property
+ * @param {Token} last - Last object property
+ * @returns {boolean} `true` if node needs to be checked for missing line breaks
+ */
+function areLineBreaksRequired(node, options, first, last) {
+    let objectProperties;
+
+    if (node.type === "ObjectExpression" || node.type === "ObjectPattern") {
+        objectProperties = node.properties;
+    } else {
+
+        // is ImportDeclaration or ExportNamedDeclaration
+        objectProperties = node.specifiers;
+    }
+
+    return objectProperties.length >= options.minProperties ||
+        (
+            options.multiline &&
+            objectProperties.length > 0 &&
+            first.loc.start.line !== last.loc.end.line
+        );
 }
 
 //------------------------------------------------------------------------------
@@ -109,7 +148,9 @@ module.exports = {
                         type: "object",
                         properties: {
                             ObjectExpression: OPTION_VALUE,
-                            ObjectPattern: OPTION_VALUE
+                            ObjectPattern: OPTION_VALUE,
+                            ImportDeclaration: OPTION_VALUE,
+                            ExportDeclaration: OPTION_VALUE
                         },
                         additionalProperties: false,
                         minProperties: 1
@@ -125,32 +166,37 @@ module.exports = {
 
         /**
          * Reports a given node if it violated this rule.
-         *
-         * @param {ASTNode} node - A node to check. This is an ObjectExpression node or an ObjectPattern node.
-         * @param {{multiline: boolean, minProperties: number}} options - An option object.
+         * @param {ASTNode} node - A node to check. This is an ObjectExpression, ObjectPattern, ImportDeclaration or ExportNamedDeclaration node.
+         * @param {{multiline: boolean, minProperties: number, consistent: boolean}} options - An option object.
          * @returns {void}
          */
         function check(node) {
             const options = normalizedOptions[node.type];
+
+            if (
+                (node.type === "ImportDeclaration" &&
+                    !node.specifiers.some(specifier => specifier.type === "ImportSpecifier")) ||
+                (node.type === "ExportNamedDeclaration" &&
+                    !node.specifiers.some(specifier => specifier.type === "ExportSpecifier"))
+            ) {
+                return;
+            }
+
             const openBrace = sourceCode.getFirstToken(node, token => token.value === "{");
+
             let closeBrace;
 
             if (node.typeAnnotation) {
                 closeBrace = sourceCode.getTokenBefore(node.typeAnnotation);
             } else {
-                closeBrace = sourceCode.getLastToken(node);
+                closeBrace = sourceCode.getLastToken(node, token => token.value === "}");
             }
 
             let first = sourceCode.getTokenAfter(openBrace, { includeComments: true });
             let last = sourceCode.getTokenBefore(closeBrace, { includeComments: true });
-            const needsLinebreaks = (
-                node.properties.length >= options.minProperties ||
-                (
-                    options.multiline &&
-                    node.properties.length > 0 &&
-                    first.loc.start.line !== last.loc.end.line
-                )
-            );
+
+            const needsLineBreaks = areLineBreaksRequired(node, options, first, last);
+
             const hasCommentsFirstToken = astUtils.isCommentToken(first);
             const hasCommentsLastToken = astUtils.isCommentToken(last);
 
@@ -165,7 +211,7 @@ module.exports = {
             first = sourceCode.getTokenAfter(openBrace);
             last = sourceCode.getTokenBefore(closeBrace);
 
-            if (needsLinebreaks) {
+            if (needsLineBreaks) {
                 if (astUtils.isTokenOnSameLine(openBrace, first)) {
                     context.report({
                         message: "Expected a line break after this opening brace.",
@@ -244,7 +290,9 @@ module.exports = {
 
         return {
             ObjectExpression: check,
-            ObjectPattern: check
+            ObjectPattern: check,
+            ImportDeclaration: check,
+            ExportNamedDeclaration: check
         };
     }
 };
diff --git a/lib/rules/object-shorthand.js b/lib/rules/object-shorthand.js
index c6c0b1044..c5239a71d 100644
--- a/lib/rules/object-shorthand.js
+++ b/lib/rules/object-shorthand.js
@@ -131,7 +131,7 @@ module.exports = {
          *
          */
         function canHaveShorthand(property) {
-            return (property.kind !== "set" && property.kind !== "get" && property.type !== "SpreadProperty" && property.type !== "ExperimentalSpreadProperty");
+            return (property.kind !== "set" && property.kind !== "get" && property.type !== "SpreadElement" && property.type !== "SpreadProperty" && property.type !== "ExperimentalSpreadProperty");
         }
 
         /**
@@ -233,10 +233,11 @@ module.exports = {
             const keyText = sourceCode.text.slice(firstKeyToken.range[0], lastKeyToken.range[1]);
             let keyPrefix = "";
 
+            if (node.value.async) {
+                keyPrefix += "async ";
+            }
             if (node.value.generator) {
-                keyPrefix = "*";
-            } else if (node.value.async) {
-                keyPrefix = "async ";
+                keyPrefix += "*";
             }
 
             if (node.value.type === "FunctionExpression") {
@@ -273,10 +274,11 @@ module.exports = {
             const keyText = sourceCode.text.slice(firstKeyToken.range[0], lastKeyToken.range[1]);
             let functionHeader = "function";
 
+            if (node.value.async) {
+                functionHeader = `async ${functionHeader}`;
+            }
             if (node.value.generator) {
-                functionHeader = "function*";
-            } else if (node.value.async) {
-                functionHeader = "async function";
+                functionHeader = `${functionHeader}*`;
             }
 
             return fixer.replaceTextRange([node.range[0], lastKeyToken.range[1]], `${keyText}: ${functionHeader}`);
diff --git a/lib/rules/require-await.js b/lib/rules/require-await.js
index 6adc84ae1..5517cf867 100644
--- a/lib/rules/require-await.js
+++ b/lib/rules/require-await.js
@@ -90,6 +90,11 @@ module.exports = {
 
             AwaitExpression() {
                 scopeInfo.hasAwait = true;
+            },
+            ForOfStatement(node) {
+                if (node.await) {
+                    scopeInfo.hasAwait = true;
+                }
             }
         };
     }
diff --git a/lib/rules/rest-spread-spacing.js b/lib/rules/rest-spread-spacing.js
index 1fbc2c4cc..e87d88129 100644
--- a/lib/rules/rest-spread-spacing.js
+++ b/lib/rules/rest-spread-spacing.js
@@ -47,9 +47,15 @@ module.exports = {
             switch (node.type) {
                 case "SpreadElement":
                     type = "spread";
+                    if (node.parent.type === "ObjectExpression") {
+                        type += " property";
+                    }
                     break;
                 case "RestElement":
                     type = "rest";
+                    if (node.parent.type === "ObjectPattern") {
+                        type += " property";
+                    }
                     break;
                 case "ExperimentalSpreadProperty":
                     type = "spread property";
diff --git a/lib/util/glob-util.js b/lib/util/glob-util.js
index 6a1f150a5..e4b78270a 100644
--- a/lib/util/glob-util.js
+++ b/lib/util/glob-util.js
@@ -8,7 +8,8 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const fs = require("fs"),
+const lodash = require("lodash"),
+    fs = require("fs"),
     path = require("path"),
     GlobSync = require("./glob"),
 
@@ -88,6 +89,8 @@ function resolveFileGlobPatterns(patterns, options) {
     return patterns.filter(p => p.length).map(processPathExtensions);
 }
 
+const dotfilesPattern = /(?:(?:^\.)|(?:[/\\]\.))[^/\\.].*/;
+
 /**
  * Build a list of absolute filesnames on which ESLint will act.
  * Ignored files are excluded from the results, as are duplicates.
@@ -107,6 +110,11 @@ function listFilesToProcess(globPatterns, options) {
 
     const cwd = (options && options.cwd) || process.cwd();
 
+    const getIgnorePaths = lodash.memoize(
+        optionsObj =>
+            new IgnoredPaths(optionsObj)
+    );
+
     /**
      * Executes the linter on a file defined by the `filename`. Skips
      * unsupported file extensions and any files that are already linted.
@@ -151,15 +159,20 @@ function listFilesToProcess(globPatterns, options) {
         const file = path.resolve(cwd, pattern);
 
         if (fs.existsSync(file) && fs.statSync(file).isFile()) {
-            const ignoredPaths = new IgnoredPaths(options);
+            const ignoredPaths = getIgnorePaths(options);
 
             addFile(fs.realpathSync(file), true, ignoredPaths);
         } else {
 
             // regex to find .hidden or /.hidden patterns, but not ./relative or ../relative
-            const globIncludesDotfiles = /(?:(?:^\.)|(?:[/\\]\.))[^/\\.].*/.test(pattern);
+            const globIncludesDotfiles = dotfilesPattern.test(pattern);
+            let newOptions = options;
+
+            if (!options.dotfiles) {
+                newOptions = Object.assign({}, options, { dotfiles: globIncludesDotfiles });
+            }
 
-            const ignoredPaths = new IgnoredPaths(Object.assign({}, options, { dotfiles: options.dotfiles || globIncludesDotfiles }));
+            const ignoredPaths = getIgnorePaths(newOptions);
             const shouldIgnore = ignoredPaths.getIgnoredFoldersGlobChecker();
             const globOptions = {
                 nodir: true,


Test patch:
diff --git a/tests/lib/linter.js b/tests/lib/linter.js
index fc4298d56..5f42ffd9c 100644
--- a/tests/lib/linter.js
+++ b/tests/lib/linter.js
@@ -1889,7 +1889,7 @@ describe("Linter", () => {
         });
     });
 
-    describe("when evaluating code with comments to ignore reporting on of specific rules on a specific line", () => {
+    describe("when evaluating code with comments to ignore reporting on specific rules on a specific line", () => {
 
         describe("eslint-disable-line", () => {
             it("should report a violation", () => {
@@ -1931,14 +1931,15 @@ describe("Linter", () => {
                 assert.strictEqual(messages[0].ruleId, "no-alert");
             });
 
-            it("should report a violation", () => {
+            it("should report a violation if eslint-disable-line in a block comment is not on a single line", () => {
                 const code = [
-                    "alert('test'); // eslint-disable-line no-alert",
-                    "alert('test'); /*eslint-disable-line no-alert*/" // here
+                    "/* eslint-disable-line",
+                    "*",
+                    "*/ console.log('test');" // here
                 ].join("\n");
                 const config = {
                     rules: {
-                        "no-alert": 1
+                        "no-console": 1
                     }
                 };
 
@@ -1946,7 +1947,44 @@ describe("Linter", () => {
 
                 assert.strictEqual(messages.length, 1);
 
+                assert.strictEqual(messages[0].ruleId, "no-console");
+            });
+
+            it("should report a violation if eslint-disable-line in a block comment is not on a single line", () => {
+                const code = [
+                    "alert('test'); /* eslint-disable-line ",
+                    "no-alert */"
+                ].join("\n");
+                const config = {
+                    rules: {
+                        "no-alert": 1,
+                        quotes: [1, "double"],
+                        semi: [1, "always"]
+                    }
+                };
+
+                const messages = linter.verify(code, config, filename);
+
+                assert.strictEqual(messages.length, 2);
+
                 assert.strictEqual(messages[0].ruleId, "no-alert");
+                assert.strictEqual(messages[1].ruleId, "quotes");
+            });
+
+            it("should not report a violation for eslint-disable-line in block comment", () => {
+                const code = [
+                    "alert('test'); // eslint-disable-line no-alert",
+                    "alert('test'); /*eslint-disable-line no-alert*/"
+                ].join("\n");
+                const config = {
+                    rules: {
+                        "no-alert": 1
+                    }
+                };
+
+                const messages = linter.verify(code, config, filename);
+
+                assert.strictEqual(messages.length, 0);
             });
 
             it("should not report a violation", () => {
@@ -1984,6 +2022,40 @@ describe("Linter", () => {
 
                 assert.strictEqual(messages.length, 0);
             });
+
+            it("should not report a violation", () => {
+                const code = [
+                    "alert('test') /* eslint-disable-line no-alert, quotes, semi */",
+                    "console.log('test'); /* eslint-disable-line */"
+                ].join("\n");
+                const config = {
+                    rules: {
+                        "no-alert": 1,
+                        quotes: [1, "double"],
+                        semi: [1, "always"],
+                        "no-console": 1
+                    }
+                };
+
+                const messages = linter.verify(code, config, filename);
+
+                assert.strictEqual(messages.length, 0);
+            });
+
+            it("should ignore violations of multiple rules when specified in mixed comments", () => {
+                const code = [
+                    " alert(\"test\"); /* eslint-disable-line no-alert */ // eslint-disable-line quotes"
+                ].join("\n");
+                const config = {
+                    rules: {
+                        "no-alert": 1,
+                        quotes: [1, "single"]
+                    }
+                };
+                const messages = linter.verify(code, config, filename);
+
+                assert.strictEqual(messages.length, 0);
+            });
         });
 
         describe("eslint-disable-next-line", () => {
@@ -2005,6 +2077,54 @@ describe("Linter", () => {
                 assert.strictEqual(messages[0].ruleId, "no-console");
             });
 
+            it("should ignore violation of specified rule if eslint-disable-next-line is a block comment", () => {
+                const code = [
+                    "/* eslint-disable-next-line no-alert */",
+                    "alert('test');",
+                    "console.log('test');"
+                ].join("\n");
+                const config = {
+                    rules: {
+                        "no-alert": 1,
+                        "no-console": 1
+                    }
+                };
+                const messages = linter.verify(code, config, filename);
+
+                assert.strictEqual(messages.length, 1);
+                assert.strictEqual(messages[0].ruleId, "no-console");
+            });
+            it("should ignore violation of specified rule if eslint-disable-next-line is a block comment", () => {
+                const code = [
+                    "/* eslint-disable-next-line no-alert */",
+                    "alert('test');"
+                ].join("\n");
+                const config = {
+                    rules: {
+                        "no-alert": 1
+                    }
+                };
+                const messages = linter.verify(code, config, filename);
+
+                assert.strictEqual(messages.length, 0);
+            });
+
+            it("should not ignore violation if block comment is not on a single line", () => {
+                const code = [
+                    "/* eslint-disable-next-line",
+                    "no-alert */alert('test');"
+                ].join("\n");
+                const config = {
+                    rules: {
+                        "no-alert": 1
+                    }
+                };
+                const messages = linter.verify(code, config, filename);
+
+                assert.strictEqual(messages.length, 1);
+                assert.strictEqual(messages[0].ruleId, "no-alert");
+            });
+
             it("should ignore violations only of specified rule", () => {
                 const code = [
                     "// eslint-disable-next-line no-console",
@@ -2043,6 +2163,22 @@ describe("Linter", () => {
                 assert.strictEqual(messages[0].ruleId, "no-console");
             });
 
+            it("should ignore violations of multiple rules when specified in mixed comments", () => {
+                const code = [
+                    "/* eslint-disable-next-line no-alert */ // eslint-disable-next-line quotes",
+                    "alert(\"test\");"
+                ].join("\n");
+                const config = {
+                    rules: {
+                        "no-alert": 1,
+                        quotes: [1, "single"]
+                    }
+                };
+                const messages = linter.verify(code, config, filename);
+
+                assert.strictEqual(messages.length, 0);
+            });
+
             it("should ignore violations of only the specified rule on next line", () => {
                 const code = [
                     "// eslint-disable-next-line quotes",
@@ -2103,7 +2239,7 @@ describe("Linter", () => {
                 assert.strictEqual(messages[0].ruleId, "no-console");
             });
 
-            it("should not ignore violations if comment is in block quotes", () => {
+            it("should ignore violations if eslint-disable-next-line is a block comment", () => {
                 const code = [
                     "alert('test');",
                     "/* eslint-disable-next-line no-alert */",
@@ -2118,10 +2254,30 @@ describe("Linter", () => {
                 };
                 const messages = linter.verify(code, config, filename);
 
-                assert.strictEqual(messages.length, 3);
+                assert.strictEqual(messages.length, 2);
                 assert.strictEqual(messages[0].ruleId, "no-alert");
-                assert.strictEqual(messages[1].ruleId, "no-alert");
-                assert.strictEqual(messages[2].ruleId, "no-console");
+                assert.strictEqual(messages[1].ruleId, "no-console");
+            });
+
+            it("should report a violation", () => {
+                const code = [
+                    "/* eslint-disable-next-line",
+                    "*",
+                    "*/",
+                    "console.log('test');" // here
+                ].join("\n");
+                const config = {
+                    rules: {
+                        "no-alert": 1,
+                        "no-console": 1
+                    }
+                };
+
+                const messages = linter.verify(code, config, filename);
+
+                assert.strictEqual(messages.length, 1);
+
+                assert.strictEqual(messages[0].ruleId, "no-console");
             });
 
             it("should not ignore violations if comment is of the type Shebang", () => {
diff --git a/tests/lib/rules/comma-dangle.js b/tests/lib/rules/comma-dangle.js
index 29027e949..0a8403ebc 100644
--- a/tests/lib/rules/comma-dangle.js
+++ b/tests/lib/rules/comma-dangle.js
@@ -134,6 +134,11 @@ ruleTester.run("comma-dangle", rule, {
             options: ["always"],
             parserOptions: { ecmaVersion: 8, ecmaFeatures: { experimentalObjectRestSpread: true } }
         },
+        {
+            code: "var {foo, ...bar} = baz",
+            options: ["always"],
+            parserOptions: { ecmaVersion: 2018 }
+        },
 
         // https://github.com/eslint/eslint/issues/3794
         {
diff --git a/tests/lib/rules/generator-star-spacing.js b/tests/lib/rules/generator-star-spacing.js
index 5108091ff..8d378cb5b 100644
--- a/tests/lib/rules/generator-star-spacing.js
+++ b/tests/lib/rules/generator-star-spacing.js
@@ -16,7 +16,7 @@ const rule = require("../../../lib/rules/generator-star-spacing"),
 // Tests
 //------------------------------------------------------------------------------
 
-const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } });
+const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 2018 } });
 
 ruleTester.run("generator-star-spacing", rule, {
 
@@ -1336,6 +1336,80 @@ ruleTester.run("generator-star-spacing", rule, {
                 message: "Missing space before *.",
                 type: "Punctuator"
             }]
+        },
+
+        // async generators
+        {
+            code: "({ async * foo(){} })",
+            output: "({ async*foo(){} })",
+            options: [{ before: false, after: false }],
+            errors: [{
+                message: "Unexpected space before *.",
+                type: "Punctuator"
+            }, {
+                message: "Unexpected space after *.",
+                type: "Punctuator"
+            }]
+        },
+        {
+            code: "({ async*foo(){} })",
+            output: "({ async * foo(){} })",
+            options: [{ before: true, after: true }],
+            errors: [{
+                message: "Missing space before *.",
+                type: "Punctuator"
+            }, {
+                message: "Missing space after *.",
+                type: "Punctuator"
+            }]
+        },
+        {
+            code: "class Foo { async * foo(){} }",
+            output: "class Foo { async*foo(){} }",
+            options: [{ before: false, after: false }],
+            errors: [{
+                message: "Unexpected space before *.",
+                type: "Punctuator"
+            }, {
+                message: "Unexpected space after *.",
+                type: "Punctuator"
+            }]
+        },
+        {
+            code: "class Foo { async*foo(){} }",
+            output: "class Foo { async * foo(){} }",
+            options: [{ before: true, after: true }],
+            errors: [{
+                message: "Missing space before *.",
+                type: "Punctuator"
+            }, {
+                message: "Missing space after *.",
+                type: "Punctuator"
+            }]
+        },
+        {
+            code: "class Foo { static async * foo(){} }",
+            output: "class Foo { static async*foo(){} }",
+            options: [{ before: false, after: false }],
+            errors: [{
+                message: "Unexpected space before *.",
+                type: "Punctuator"
+            }, {
+                message: "Unexpected space after *.",
+                type: "Punctuator"
+            }]
+        },
+        {
+            code: "class Foo { static async*foo(){} }",
+            output: "class Foo { static async * foo(){} }",
+            options: [{ before: true, after: true }],
+            errors: [{
+                message: "Missing space before *.",
+                type: "Punctuator"
+            }, {
+                message: "Missing space after *.",
+                type: "Punctuator"
+            }]
         }
 
     ]
diff --git a/tests/lib/rules/indent.js b/tests/lib/rules/indent.js
index 6ffa72ce4..3a6bc0c99 100644
--- a/tests/lib/rules/indent.js
+++ b/tests/lib/rules/indent.js
@@ -4694,6 +4694,15 @@ ruleTester.run("indent", rule, {
             `,
             options: [4, { ignoredNodes: ["JSXOpeningElement"] }]
         },
+        {
+            code: unIndent`
+                foo &&
+                <Bar
+                >
+                </Bar>
+            `,
+            options: [4, { ignoredNodes: ["JSXElement", "JSXOpeningElement"] }]
+        },
         {
             code: unIndent`
                 (function($) {
diff --git a/tests/lib/rules/key-spacing.js b/tests/lib/rules/key-spacing.js
index 5fa42b999..183c91eb0 100644
--- a/tests/lib/rules/key-spacing.js
+++ b/tests/lib/rules/key-spacing.js
@@ -383,6 +383,78 @@ ruleTester.run("key-spacing", rule, {
             align: "colon"
         }],
         parserOptions: { ecmaVersion: 6, ecmaFeatures: { experimentalObjectRestSpread: true } }
+    }, {
+        code: "({a : foo, ...x, b : bar})['a'];",
+        options: [{
+            beforeColon: true,
+            afterColon: true
+        }],
+        parserOptions: { ecmaVersion: 2018 }
+    }, {
+        code: [
+            "var obj = {",
+            "    'a'     : (42 - 12),",
+            "    ...x,",
+            "    foobar  : 'value',",
+            "    [(expr)]: val",
+            "};"
+        ].join("\n"),
+        options: [{
+            align: "colon"
+        }],
+        parserOptions: { ecmaVersion: 2018 }
+    }, {
+        code: [
+            "callExpr(arg, {",
+            "    key       :val,",
+            "    ...x,",
+            "    ...y,",
+            "    'another' :false,",
+            "    [compute] :'value'",
+            "});"
+        ].join("\n"),
+        options: [{
+            align: "colon",
+            beforeColon: true,
+            afterColon: false
+        }],
+        parserOptions: { ecmaVersion: 2018 }
+    }, {
+        code: [
+            "var obj = {",
+            "    a:        (42 - 12),",
+            "    ...x,",
+            "    'foobar': 'value',",
+            "    bat:      function() {",
+            "        return this.a;",
+            "    },",
+            "    baz: 42",
+            "};"
+        ].join("\n"),
+        options: [{
+            align: "value"
+        }],
+        parserOptions: { ecmaVersion: 2018 }
+    }, {
+        code: [
+            "({",
+            "    ...x,",
+            "    a  : 0,",
+            "    // same group",
+            "    bcd: 0, /*",
+            "    end of group */",
+            "",
+            "    // different group",
+            "    e: 0,",
+            "    ...y,",
+            "    /* group b */",
+            "    f: 0",
+            "})"
+        ].join("\n"),
+        options: [{
+            align: "colon"
+        }],
+        parserOptions: { ecmaVersion: 2018 }
     },
 
     // https://github.com/eslint/eslint/issues/4792
@@ -524,7 +596,7 @@ ruleTester.run("key-spacing", rule, {
             beforeColon: true,
             afterColon: false
         }],
-        parserOptions: { ecmaVersion: 6, ecmaFeatures: { experimentalObjectRestSpread: true } }
+        parserOptions: { ecmaVersion: 6 }
     }, {
         code: [
             "({",
@@ -543,7 +615,7 @@ ruleTester.run("key-spacing", rule, {
             beforeColon: true,
             afterColon: false
         }],
-        parserOptions: { ecmaVersion: 6, ecmaFeatures: { experimentalObjectRestSpread: true } }
+        parserOptions: { ecmaVersion: 6 }
     }, {
         code: [
             "({",
@@ -561,7 +633,7 @@ ruleTester.run("key-spacing", rule, {
                 }
             }
         }],
-        parserOptions: { ecmaVersion: 6, ecmaFeatures: { experimentalObjectRestSpread: true } }
+        parserOptions: { ecmaVersion: 6 }
     }, {
         code: [
             "({",
@@ -577,7 +649,7 @@ ruleTester.run("key-spacing", rule, {
                 afterColon: false
             }
         }],
-        parserOptions: { ecmaVersion: 6, ecmaFeatures: { experimentalObjectRestSpread: true } },
+        parserOptions: { ecmaVersion: 6 },
         errors: []
     }, {
         code: [
@@ -595,7 +667,7 @@ ruleTester.run("key-spacing", rule, {
                 mode: "minimum"
             }
         }],
-        parserOptions: { ecmaVersion: 6, ecmaFeatures: { experimentalObjectRestSpread: true } }
+        parserOptions: { ecmaVersion: 6 }
     }, {
         code: [
             "({",
@@ -613,7 +685,7 @@ ruleTester.run("key-spacing", rule, {
                 }
             }
         }],
-        parserOptions: { ecmaVersion: 6, ecmaFeatures: { experimentalObjectRestSpread: true } }
+        parserOptions: { ecmaVersion: 6 }
     }, {
         code: [
             "({",
@@ -647,7 +719,7 @@ ruleTester.run("key-spacing", rule, {
                 afterColon: true
             }
         }],
-        parserOptions: { ecmaVersion: 6, ecmaFeatures: { experimentalObjectRestSpread: true } }
+        parserOptions: { ecmaVersion: 6 }
     }, {
         code: [
             "({",
@@ -678,7 +750,7 @@ ruleTester.run("key-spacing", rule, {
                 afterColon: true
             }
         }],
-        parserOptions: { ecmaVersion: 6, ecmaFeatures: { experimentalObjectRestSpread: true } }
+        parserOptions: { ecmaVersion: 6 }
     }, {
         code: [
             "({",
@@ -706,7 +778,7 @@ ruleTester.run("key-spacing", rule, {
                 afterColon: false
             }
         }],
-        parserOptions: { ecmaVersion: 6, ecmaFeatures: { experimentalObjectRestSpread: true } }
+        parserOptions: { ecmaVersion: 6 }
     }, {
         code: [
             "var obj = {",
@@ -731,7 +803,7 @@ ruleTester.run("key-spacing", rule, {
                 }
             }
         }],
-        parserOptions: { ecmaVersion: 6, ecmaFeatures: { experimentalObjectRestSpread: true } }
+        parserOptions: { ecmaVersion: 6 }
     }, {
         code: [
             "var obj = {",
@@ -756,7 +828,7 @@ ruleTester.run("key-spacing", rule, {
                 mode: "minimum"
             }
         }],
-        parserOptions: { ecmaVersion: 6, ecmaFeatures: { experimentalObjectRestSpread: true } }
+        parserOptions: { ecmaVersion: 6 }
     }],
 
     invalid: [{
@@ -1323,6 +1395,43 @@ ruleTester.run("key-spacing", rule, {
             { message: "Missing space after key 'a'.", line: 3, column: 5, type: "Identifier" },
             { message: "Extra space after key 'f'.", line: 12, column: 5, type: "Identifier" }
         ]
+    }, {
+        code: [
+            "({",
+            "    ...x,",
+            "    a : 0,",
+            "    // same group",
+            "    bcd: 0, /*",
+            "    end of group */",
+            "",
+            "    // different group",
+            "    e: 0,",
+            "    ...y,",
+            "    /* group b */",
+            "    f : 0",
+            "})"
+        ].join("\n"),
+        output: [
+            "({",
+            "    ...x,",
+            "    a  : 0,",
+            "    // same group",
+            "    bcd: 0, /*",
+            "    end of group */",
+            "",
+            "    // different group",
+            "    e: 0,",
+            "    ...y,",
+            "    /* group b */",
+            "    f: 0",
+            "})"
+        ].join("\n"),
+        options: [{ align: "colon" }],
+        parserOptions: { ecmaVersion: 2018 },
+        errors: [
+            { message: "Missing space after key 'a'.", line: 3, column: 5, type: "Identifier" },
+            { message: "Extra space after key 'f'.", line: 12, column: 5, type: "Identifier" }
+        ]
     },
 
     // https://github.com/eslint/eslint/issues/4792
@@ -1541,6 +1650,15 @@ ruleTester.run("key-spacing", rule, {
             { message: "Missing space before value for key 'a'.", line: 1, column: 6, type: "Identifier" },
             { message: "Extra space after key 'c'.", line: 1, column: 20, type: "Identifier" }
         ]
+    }, {
+        code: "({ a:b, ...object, c : d })",
+        output: "({ a: b, ...object, c: d })",
+        options: [{ align: "colon" }],
+        parserOptions: { ecmaVersion: 2018 },
+        errors: [
+            { message: "Missing space before value for key 'a'.", line: 1, column: 6, type: "Identifier" },
+            { message: "Extra space after key 'c'.", line: 1, column: 20, type: "Identifier" }
+        ]
     },
 
     // https://github.com/eslint/eslint/issues/5613
@@ -1567,7 +1685,7 @@ ruleTester.run("key-spacing", rule, {
                 mode: "strict"
             }
         }],
-        parserOptions: { ecmaVersion: 6, ecmaFeatures: { experimentalObjectRestSpread: true } },
+        parserOptions: { ecmaVersion: 6 },
         errors: [
             { message: "Missing space after key 'longName'.", line: 2, column: 5, type: "Identifier" },
             { message: "Missing space before value for key 'longName'.", line: 2, column: 14, type: "Literal" },
@@ -1615,7 +1733,7 @@ ruleTester.run("key-spacing", rule, {
                 mode: "strict"
             }
         }],
-        parserOptions: { ecmaVersion: 6, ecmaFeatures: { experimentalObjectRestSpread: true } },
+        parserOptions: { ecmaVersion: 6 },
         errors: [
             { message: "Missing space before value for key 'func'.", line: 2, column: 10, type: "FunctionExpression" },
             { message: "Missing space after key 'longName'.", line: 5, column: 5, type: "Identifier" },
@@ -1664,7 +1782,7 @@ ruleTester.run("key-spacing", rule, {
                 }
             }
         }],
-        parserOptions: { ecmaVersion: 6, ecmaFeatures: { experimentalObjectRestSpread: true } },
+        parserOptions: { ecmaVersion: 6 },
         errors: [
             { message: "Missing space before value for key 'func'.", line: 2, column: 10, type: "FunctionExpression" },
             { message: "Missing space after key 'small'.", line: 6, column: 5, type: "Identifier" },
@@ -1706,7 +1824,7 @@ ruleTester.run("key-spacing", rule, {
                 }
             }
         }],
-        parserOptions: { ecmaVersion: 6, ecmaFeatures: { experimentalObjectRestSpread: true } },
+        parserOptions: { ecmaVersion: 6 },
         errors: [
             { message: "Extra space before value for key 'key2'.", line: 4, column: 14, type: "Literal" },
             { message: "Extra space before value for key 'key3'.", line: 5, column: 14, type: "Literal" }
@@ -1744,7 +1862,7 @@ ruleTester.run("key-spacing", rule, {
                 on: "colon"
             }
         }],
-        parserOptions: { ecmaVersion: 6, ecmaFeatures: { experimentalObjectRestSpread: true } },
+        parserOptions: { ecmaVersion: 6 },
         errors: [
             { message: "Extra space before value for key 'key2'.", line: 4, column: 14, type: "Literal" },
             { message: "Extra space before value for key 'key3'.", line: 5, column: 14, type: "Literal" }
diff --git a/tests/lib/rules/keyword-spacing.js b/tests/lib/rules/keyword-spacing.js
index d97f819fb..2ab9b5d35 100644
--- a/tests/lib/rules/keyword-spacing.js
+++ b/tests/lib/rules/keyword-spacing.js
@@ -180,6 +180,10 @@ ruleTester.run("keyword-spacing", rule, {
         { code: "a[ async function foo() {}]", options: [NEITHER], parserOptions: { ecmaVersion: 8 } },
         { code: "({[ async function foo() {}]: 0})", options: [NEITHER], parserOptions: { ecmaVersion: 8 } },
 
+        // not conflict with `generator-star-spacing`
+        { code: "({ async* foo() {} })", parserOptions: { ecmaVersion: 2018 } },
+        { code: "({ async *foo() {} })", options: [NEITHER], parserOptions: { ecmaVersion: 2018 } },
+
         // not conflict with `key-spacing`
         { code: "({a:async function foo() {} })", parserOptions: { ecmaVersion: 8 } },
         { code: "({a: async function foo() {} })", options: [NEITHER], parserOptions: { ecmaVersion: 8 } },
@@ -1530,6 +1534,34 @@ ruleTester.run("keyword-spacing", rule, {
             errors: unexpectedBefore("await")
         },
 
+        {
+            code: "async function wrap() { for await(x of xs); }",
+            output: "async function wrap() { for await (x of xs); }",
+            parserOptions: { ecmaVersion: 2018 },
+            errors: expectedAfter("await")
+        },
+        {
+            code: "async function wrap() { for await (x of xs); }",
+            output: "async function wrap() { for await(x of xs); }",
+            options: [NEITHER],
+            parserOptions: { ecmaVersion: 2018 },
+            errors: unexpectedAfter("await")
+        },
+        {
+            code: "async function wrap() { for await(x of xs); }",
+            output: "async function wrap() { for await (x of xs); }",
+            options: [override("await", BOTH)],
+            parserOptions: { ecmaVersion: 2018 },
+            errors: expectedAfter("await")
+        },
+        {
+            code: "async function wrap() { for await (x of xs); }",
+            output: "async function wrap() { for await(x of xs); }",
+            options: [override("await", NEITHER)],
+            parserOptions: { ecmaVersion: 2018 },
+            errors: unexpectedAfter("await")
+        },
+
         //----------------------------------------------------------------------
         // break
         //----------------------------------------------------------------------
diff --git a/tests/lib/rules/no-await-in-loop.js b/tests/lib/rules/no-await-in-loop.js
index bb74db1c0..057223879 100644
--- a/tests/lib/rules/no-await-in-loop.js
+++ b/tests/lib/rules/no-await-in-loop.js
@@ -10,13 +10,14 @@ const rule = require("../../../lib/rules/no-await-in-loop"),
 
 const error = { messageId: "unexpectedAwait" };
 
-const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: "2017" } });
+const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 2018 } });
 
 ruleTester.run("no-await-in-loop", rule, {
     valid: [
         "async function foo() { await bar; }",
         "async function foo() { for (var bar in await baz) { } }",
         "async function foo() { for (var bar of await baz) { } }",
+        "async function foo() { for await (var bar of await baz) { } }",
         "async function foo() { for (var bar = await baz in qux) {} }",
 
         // While loops
@@ -35,14 +36,17 @@ ruleTester.run("no-await-in-loop", rule, {
         "async function foo() { while (true) { var y = async () => { await foo; } } }",
 
         // Blocked by a class method
-        "async function foo() { while (true) { class Foo { async foo() { await bar; } } } }"
+        "async function foo() { while (true) { class Foo { async foo() { await bar; } } } }",
 
+        // Asynchronous iteration intentionally
+        "async function foo() { for await (var x of xs) { await f(x) } }"
     ],
     invalid: [
 
         // While loops
         { code: "async function foo() { while (baz) { await bar; } }", errors: [error] },
         { code: "async function foo() { while (await foo()) {  } }", errors: [error] },
+        { code: "async function foo() { while (baz) { for await (x of xs); } }", errors: [error] },
 
         // For of loops
         { code: "async function foo() { for (var bar of baz) { await bar; } }", errors: [error] },
@@ -64,6 +68,9 @@ ruleTester.run("no-await-in-loop", rule, {
         { code: "async function foo() { while (true) { if (bar) { foo(await bar); } } }", errors: [error] },
 
         // Deep in a loop condition
-        { code: "async function foo() { while (xyz || 5 > await x) {  } }", errors: [error] }
+        { code: "async function foo() { while (xyz || 5 > await x) {  } }", errors: [error] },
+
+        // In a nested loop of for-await-of
+        { code: "async function foo() { for await (var x of xs) { while (1) await f(x) } }", errors: [error] }
     ]
 });
diff --git a/tests/lib/rules/no-dupe-keys.js b/tests/lib/rules/no-dupe-keys.js
index c8ca43b54..aeccfb4ce 100644
--- a/tests/lib/rules/no-dupe-keys.js
+++ b/tests/lib/rules/no-dupe-keys.js
@@ -25,6 +25,7 @@ ruleTester.run("no-dupe-keys", rule, {
         "+{ get a() { }, set a(b) { } };",
         { code: "var x = { a: b, [a]: b };", parserOptions: { ecmaVersion: 6 } },
         { code: "var x = { a: b, ...c }", parserOptions: { ecmaVersion: 6, ecmaFeatures: { experimentalObjectRestSpread: true } } },
+        { code: "var x = { a: b, ...c }", parserOptions: { ecmaVersion: 2018 } },
         { code: "var x = { get a() {}, set a (value) {} };", parserOptions: { ecmaVersion: 6 } },
         { code: "var x = { a: 1, b: { a: 2 } };", parserOptions: { ecmaVersion: 6 } },
         { code: "var {a, a} = obj", parserOptions: { ecmaVersion: 6 } }
diff --git a/tests/lib/rules/no-extra-parens.js b/tests/lib/rules/no-extra-parens.js
index 3df00d516..93d669f88 100644
--- a/tests/lib/rules/no-extra-parens.js
+++ b/tests/lib/rules/no-extra-parens.js
@@ -46,9 +46,8 @@ function invalid(code, output, type, line, config) {
 
 const ruleTester = new RuleTester({
     parserOptions: {
-        ecmaVersion: 8,
+        ecmaVersion: 2018,
         ecmaFeatures: {
-            experimentalObjectRestSpread: true,
             jsx: true
         }
     }
@@ -409,8 +408,16 @@ ruleTester.run("no-extra-parens", rule, {
 
         "let a = [ ...b ]",
         "let a = { ...b }",
+        {
+            code: "let a = { ...b }",
+            parserOptions: { ecmaFeatures: { experimentalObjectRestSpread: true } }
+        },
         "let a = [ ...(b, c) ]",
         "let a = { ...(b, c) }",
+        {
+            code: "let a = { ...(b, c) }",
+            parserOptions: { ecmaFeatures: { experimentalObjectRestSpread: true } }
+        },
         "var [x = (1, foo)] = bar",
         "class A extends B {}",
         "const A = class extends B {}",
@@ -954,6 +961,13 @@ ruleTester.run("no-extra-parens", rule, {
             "Identifier",
             1
         ),
+        invalid(
+            "let a = {...(b)}",
+            "let a = {...b}",
+            "Identifier",
+            1,
+            { parserOptions: { ecmaFeatures: { experimentalObjectRestSpread: true } } }
+        ),
         invalid(
             "let a = [...((b, c))]",
             "let a = [...(b, c)]",
@@ -966,6 +980,13 @@ ruleTester.run("no-extra-parens", rule, {
             "SequenceExpression",
             1
         ),
+        invalid(
+            "let a = {...((b, c))}",
+            "let a = {...(b, c)}",
+            "SequenceExpression",
+            1,
+            { parserOptions: { ecmaFeatures: { experimentalObjectRestSpread: true } } }
+        ),
         invalid(
             "class A extends (B) {}",
             "class A extends B {}",
diff --git a/tests/lib/rules/no-param-reassign.js b/tests/lib/rules/no-param-reassign.js
index f894e1142..5d009c338 100644
--- a/tests/lib/rules/no-param-reassign.js
+++ b/tests/lib/rules/no-param-reassign.js
@@ -41,6 +41,16 @@ ruleTester.run("no-param-reassign", rule, {
             code: "function foo(a) { ({ [a]: variable } = value) }",
             options: [{ props: true }],
             parserOptions: { ecmaVersion: 6 }
+        },
+        {
+            code: "function foo(a) { ([...a.b] = obj); }",
+            options: [{ props: false }],
+            parserOptions: { ecmaVersion: 2015 }
+        },
+        {
+            code: "function foo(a) { ({...a.b} = obj); }",
+            options: [{ props: false }],
+            parserOptions: { ecmaVersion: 2018 }
         }
     ],
 
@@ -100,6 +110,28 @@ ruleTester.run("no-param-reassign", rule, {
             options: [{ props: true }],
             parserOptions: { ecmaVersion: 6 },
             errors: [{ message: "Assignment to function parameter 'a'." }]
+        },
+        {
+            code: "function foo(a) { ([...a] = obj); }",
+            parserOptions: { ecmaVersion: 2015 },
+            errors: [{ message: "Assignment to function parameter 'a'." }]
+        },
+        {
+            code: "function foo(a) { ({...a} = obj); }",
+            parserOptions: { ecmaVersion: 2018 },
+            errors: [{ message: "Assignment to function parameter 'a'." }]
+        },
+        {
+            code: "function foo(a) { ([...a.b] = obj); }",
+            options: [{ props: true }],
+            parserOptions: { ecmaVersion: 2015 },
+            errors: [{ message: "Assignment to property of function parameter 'a'." }]
+        },
+        {
+            code: "function foo(a) { ({...a.b} = obj); }",
+            options: [{ props: true }],
+            parserOptions: { ecmaVersion: 2018 },
+            errors: [{ message: "Assignment to property of function parameter 'a'." }]
         }
     ]
 });
diff --git a/tests/lib/rules/no-self-assign.js b/tests/lib/rules/no-self-assign.js
index 76bd8b4c9..553ac4602 100644
--- a/tests/lib/rules/no-self-assign.js
+++ b/tests/lib/rules/no-self-assign.js
@@ -40,6 +40,7 @@ ruleTester.run("no-self-assign", rule, {
         { code: "({a} = {a() {}})", parserOptions: { ecmaVersion: 6 } },
         { code: "({a} = {[a]: a})", parserOptions: { ecmaVersion: 6 } },
         { code: "({a, ...b} = {a, ...b})", parserOptions: { ecmaVersion: 6, ecmaFeatures: { experimentalObjectRestSpread: true } } },
+        { code: "({a, ...b} = {a, ...b})", parserOptions: { ecmaVersion: 2018 } },
         { code: "a.b = a.c", options: [{ props: true }] },
         { code: "a.b = c.b", options: [{ props: true }] },
         { code: "a.b = a[b]", options: [{ props: true }] },
@@ -68,6 +69,7 @@ ruleTester.run("no-self-assign", rule, {
         { code: "({a, b} = {c, a})", parserOptions: { ecmaVersion: 6 }, errors: ["'a' is assigned to itself."] },
         { code: "({a: {b}, c: [d]} = {a: {b}, c: [d]})", parserOptions: { ecmaVersion: 6 }, errors: ["'b' is assigned to itself.", "'d' is assigned to itself."] },
         { code: "({a, b} = {a, ...x, b})", parserOptions: { ecmaVersion: 6, ecmaFeatures: { experimentalObjectRestSpread: true } }, errors: ["'b' is assigned to itself."] },
+        { code: "({a, b} = {a, ...x, b})", parserOptions: { ecmaVersion: 2018 }, errors: ["'b' is assigned to itself."] },
         { code: "a.b = a.b", options: [{ props: true }], errors: ["'a.b' is assigned to itself."] },
         { code: "a.b.c = a.b.c", options: [{ props: true }], errors: ["'a.b.c' is assigned to itself."] },
         { code: "a[b] = a[b]", options: [{ props: true }], errors: ["'a[b]' is assigned to itself."] },
diff --git a/tests/lib/rules/no-undef.js b/tests/lib/rules/no-undef.js
index 150e7ecbc..bf7e775a6 100644
--- a/tests/lib/rules/no-undef.js
+++ b/tests/lib/rules/no-undef.js
@@ -81,6 +81,13 @@ ruleTester.run("no-undef", rule, {
                 }
             },
             globals: { stuff: false, foo: false }
+        },
+        {
+            code: "var {bacon, ...others} = stuff; foo(others)",
+            parserOptions: {
+                ecmaVersion: 2018
+            },
+            globals: { stuff: false, foo: false }
         }
     ],
     invalid: [
@@ -107,6 +114,13 @@ ruleTester.run("no-undef", rule, {
                 }
             },
             errors: [{ message: "'b' is not defined." }]
+        },
+        {
+            code: "const c = 0; const a = {...b, c};",
+            parserOptions: {
+                ecmaVersion: 2018
+            },
+            errors: [{ message: "'b' is not defined." }]
         }
     ]
 });
diff --git a/tests/lib/rules/no-unused-vars.js b/tests/lib/rules/no-unused-vars.js
index 9615c62dd..5fd39ede7 100644
--- a/tests/lib/rules/no-unused-vars.js
+++ b/tests/lib/rules/no-unused-vars.js
@@ -34,22 +34,6 @@ ruleTester.defineRule("use-every-a", context => {
     };
 });
 
-/**
- * Returns an extended test that includes es2017 parser options.
- * @param {Object} test The test to extend
- * @returns {Object} A parser-extended test case
- */
-function includeRestPropertyParser(test) {
-    return Object.assign({
-        parserOptions: {
-            ecmaVersion: 2017,
-            ecmaFeatures: {
-                experimentalObjectRestSpread: true
-            }
-        }
-    }, test);
-}
-
 /**
  * Returns an expected error for defined-but-not-used variables.
  * @param {string} varName The name of the variable
@@ -196,10 +180,16 @@ ruleTester.run("no-unused-vars", rule, {
         },
 
         // Using object rest for variable omission
-        includeRestPropertyParser({
+        {
+            code: "const data = { type: 'coords', x: 1, y: 2 };\nconst { type, ...coords } = data;\n console.log(coords);",
+            options: [{ ignoreRestSiblings: true }],
+            parserOptions: { ecmaVersion: 2015, ecmaFeatures: { experimentalObjectRestSpread: true } }
+        },
+        {
             code: "const data = { type: 'coords', x: 1, y: 2 };\nconst { type, ...coords } = data;\n console.log(coords);",
-            options: [{ ignoreRestSiblings: true }]
-        }),
+            options: [{ ignoreRestSiblings: true }],
+            parserOptions: { ecmaVersion: 2018 }
+        },
 
         // https://github.com/eslint/eslint/issues/6348
         "var a = 0, b; b = a = a + 1; foo(b);",
@@ -282,10 +272,16 @@ ruleTester.run("no-unused-vars", rule, {
         },
 
         // https://github.com/eslint/eslint/issues/8119
-        includeRestPropertyParser({
+        {
             code: "(({a, ...rest}) => rest)",
-            options: [{ args: "all", ignoreRestSiblings: true }]
-        })
+            options: [{ args: "all", ignoreRestSiblings: true }],
+            parserOptions: { ecmaVersion: 2015, ecmaFeatures: { experimentalObjectRestSpread: true } }
+        },
+        {
+            code: "(({a, ...rest}) => rest)",
+            options: [{ args: "all", ignoreRestSiblings: true }],
+            parserOptions: { ecmaVersion: 2018 }
+        }
     ],
     invalid: [
         { code: "function foox() { return foox(); }", errors: [definedError("foox")] },
@@ -380,52 +376,93 @@ ruleTester.run("no-unused-vars", rule, {
         },
 
         // Rest property sibling without ignoreRestSiblings
-        includeRestPropertyParser({
+        {
             code: "const data = { type: 'coords', x: 1, y: 2 };\nconst { type, ...coords } = data;\n console.log(coords);",
+            parserOptions: { ecmaVersion: 2015, ecmaFeatures: { experimentalObjectRestSpread: true } },
             errors: [
                 { line: 2, column: 9, message: "'type' is assigned a value but never used." }
             ]
-        }),
+        },
+        {
+            code: "const data = { type: 'coords', x: 1, y: 2 };\nconst { type, ...coords } = data;\n console.log(coords);",
+            parserOptions: { ecmaVersion: 2018 },
+            errors: [
+                { line: 2, column: 9, message: "'type' is assigned a value but never used." }
+            ]
+        },
 
         // Unused rest property with ignoreRestSiblings
-        includeRestPropertyParser({
+        {
             code: "const data = { type: 'coords', x: 1, y: 2 };\nconst { type, ...coords } = data;\n console.log(type)",
             options: [{ ignoreRestSiblings: true }],
+            parserOptions: { ecmaVersion: 2015, ecmaFeatures: { experimentalObjectRestSpread: true } },
             errors: [
                 { line: 2, column: 18, message: "'coords' is assigned a value but never used." }
             ]
-        }),
+        },
+        {
+            code: "const data = { type: 'coords', x: 1, y: 2 };\nconst { type, ...coords } = data;\n console.log(type)",
+            options: [{ ignoreRestSiblings: true }],
+            parserOptions: { ecmaVersion: 2018 },
+            errors: [
+                { line: 2, column: 18, message: "'coords' is assigned a value but never used." }
+            ]
+        },
 
         // Unused rest property without ignoreRestSiblings
-        includeRestPropertyParser({
+        {
             code: "const data = { type: 'coords', x: 1, y: 2 };\nconst { type, ...coords } = data;\n console.log(type)",
+            parserOptions: { ecmaVersion: 2015, ecmaFeatures: { experimentalObjectRestSpread: true } },
             errors: [
                 { line: 2, column: 18, message: "'coords' is assigned a value but never used." }
             ]
-        }),
+        },
+        {
+            code: "const data = { type: 'coords', x: 1, y: 2 };\nconst { type, ...coords } = data;\n console.log(type)",
+            parserOptions: { ecmaVersion: 2018 },
+            errors: [
+                { line: 2, column: 18, message: "'coords' is assigned a value but never used." }
+            ]
+        },
 
         // Nested array destructuring with rest property
-        includeRestPropertyParser({
+        {
+            code: "const data = { vars: ['x','y'], x: 1, y: 2 };\nconst { vars: [x], ...coords } = data;\n console.log(coords)",
+            parserOptions: { ecmaVersion: 2015, ecmaFeatures: { experimentalObjectRestSpread: true } },
+            errors: [
+                { line: 2, column: 16, message: "'x' is assigned a value but never used." }
+            ]
+        },
+        {
             code: "const data = { vars: ['x','y'], x: 1, y: 2 };\nconst { vars: [x], ...coords } = data;\n console.log(coords)",
+            parserOptions: { ecmaVersion: 2018 },
             errors: [
                 { line: 2, column: 16, message: "'x' is assigned a value but never used." }
             ]
-        }),
+        },
 
         // Nested object destructuring with rest property
-        includeRestPropertyParser({
+        {
             code: "const data = { defaults: { x: 0 }, x: 1, y: 2 };\nconst { defaults: { x }, ...coords } = data;\n console.log(coords)",
+            parserOptions: { ecmaVersion: 2015, ecmaFeatures: { experimentalObjectRestSpread: true } },
             errors: [
                 { line: 2, column: 21, message: "'x' is assigned a value but never used." }
             ]
-        }),
+        },
 
         // https://github.com/eslint/eslint/issues/8119
-        includeRestPropertyParser({
+        {
             code: "(({a, ...rest}) => {})",
             options: [{ args: "all", ignoreRestSiblings: true }],
+            parserOptions: { ecmaVersion: 2015, ecmaFeatures: { experimentalObjectRestSpread: true } },
             errors: ["'rest' is defined but never used."]
-        }),
+        },
+        {
+            code: "(({a, ...rest}) => {})",
+            options: [{ args: "all", ignoreRestSiblings: true }],
+            parserOptions: { ecmaVersion: 2018 },
+            errors: ["'rest' is defined but never used."]
+        },
 
         // https://github.com/eslint/eslint/issues/3714
         {
diff --git a/tests/lib/rules/no-useless-computed-key.js b/tests/lib/rules/no-useless-computed-key.js
index c825579fc..ed9f3daa0 100644
--- a/tests/lib/rules/no-useless-computed-key.js
+++ b/tests/lib/rules/no-useless-computed-key.js
@@ -16,7 +16,7 @@ const rule = require("../../../lib/rules/no-useless-computed-key"),
 // Tests
 //------------------------------------------------------------------------------
 
-const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } });
+const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 2018 } });
 
 ruleTester.run("no-useless-computed-key", rule, {
     valid: [
@@ -162,6 +162,12 @@ ruleTester.run("no-useless-computed-key", rule, {
             errors: [{
                 message: "Unnecessarily computed property [2] found.", type: "Property"
             }]
+        }, {
+            code: "({ async*[2]() {} })",
+            output: "({ async*2() {} })",
+            errors: [{
+                message: "Unnecessarily computed property [2] found.", type: "Property"
+            }]
         }
     ]
 });
diff --git a/tests/lib/rules/no-useless-rename.js b/tests/lib/rules/no-useless-rename.js
index 5fad7768e..325ab3cef 100644
--- a/tests/lib/rules/no-useless-rename.js
+++ b/tests/lib/rules/no-useless-rename.js
@@ -52,14 +52,26 @@ ruleTester.run("no-useless-rename", rule, {
             code: "const {...stuff} = myObject;",
             parserOptions: { ecmaFeatures: { experimentalObjectRestSpread: true } }
         },
+        {
+            code: "const {...stuff} = myObject;",
+            parserOptions: { ecmaVersion: 2018 }
+        },
         {
             code: "const {foo, ...stuff} = myObject;",
             parserOptions: { ecmaFeatures: { experimentalObjectRestSpread: true } }
         },
+        {
+            code: "const {foo, ...stuff} = myObject;",
+            parserOptions: { ecmaVersion: 2018 }
+        },
         {
             code: "const {foo: bar, ...stuff} = myObject;",
             parserOptions: { ecmaFeatures: { experimentalObjectRestSpread: true } }
         },
+        {
+            code: "const {foo: bar, ...stuff} = myObject;",
+            parserOptions: { ecmaVersion: 2018 }
+        },
 
         // { ignoreDestructuring: true }
         {
@@ -228,18 +240,36 @@ ruleTester.run("no-useless-rename", rule, {
             parserOptions: { ecmaFeatures: { experimentalObjectRestSpread: true } },
             errors: ["Destructuring assignment foo unnecessarily renamed."]
         },
+        {
+            code: "const {foo: foo, ...stuff} = myObject;",
+            output: "const {foo, ...stuff} = myObject;",
+            parserOptions: { ecmaVersion: 2018 },
+            errors: ["Destructuring assignment foo unnecessarily renamed."]
+        },
         {
             code: "const {foo: foo, bar: baz, ...stuff} = myObject;",
             output: "const {foo, bar: baz, ...stuff} = myObject;",
             parserOptions: { ecmaFeatures: { experimentalObjectRestSpread: true } },
             errors: ["Destructuring assignment foo unnecessarily renamed."]
         },
+        {
+            code: "const {foo: foo, bar: baz, ...stuff} = myObject;",
+            output: "const {foo, bar: baz, ...stuff} = myObject;",
+            parserOptions: { ecmaVersion: 2018 },
+            errors: ["Destructuring assignment foo unnecessarily renamed."]
+        },
         {
             code: "const {foo: foo, bar: bar, ...stuff} = myObject;",
             output: "const {foo, bar, ...stuff} = myObject;",
             parserOptions: { ecmaFeatures: { experimentalObjectRestSpread: true } },
             errors: ["Destructuring assignment foo unnecessarily renamed.", "Destructuring assignment bar unnecessarily renamed."]
         },
+        {
+            code: "const {foo: foo, bar: bar, ...stuff} = myObject;",
+            output: "const {foo, bar, ...stuff} = myObject;",
+            parserOptions: { ecmaVersion: 2018 },
+            errors: ["Destructuring assignment foo unnecessarily renamed.", "Destructuring assignment bar unnecessarily renamed."]
+        },
         {
             code: "import {foo as foo} from 'foo';",
             output: "import {foo} from 'foo';",
diff --git a/tests/lib/rules/object-curly-newline.js b/tests/lib/rules/object-curly-newline.js
index cdbf75750..73d9a233a 100644
--- a/tests/lib/rules/object-curly-newline.js
+++ b/tests/lib/rules/object-curly-newline.js
@@ -17,7 +17,7 @@ const resolvePath = require("path").resolve,
 // Tests
 //------------------------------------------------------------------------------
 
-const ruleTester = new RuleTester();
+const ruleTester = new RuleTester({ parserOptions: { sourceType: "module" } });
 
 ruleTester.run("object-curly-newline", rule, {
     valid: [
@@ -432,6 +432,119 @@ ruleTester.run("object-curly-newline", rule, {
             ].join("\n"),
             options: [{ ObjectExpression: "always", ObjectPattern: "never" }],
             parserOptions: { ecmaVersion: 6 }
+        },
+
+        // "ImportDeclaration" ---------------------------------------------
+        {
+            code: [
+                "import {",
+                "    a,",
+                " b",
+                "} from 'module';"
+            ].join("\n"),
+            options: [{ ImportDeclaration: "always" }]
+        },
+        {
+            code: [
+                "import {a as a, b} from 'module';"
+            ].join("\n"),
+            options: [{ ImportDeclaration: "never" }]
+        },
+        {
+            code: [
+                "import { a, } from 'module';"
+            ].join("\n"),
+            options: [{ ImportDeclaration: { multiline: true } }]
+        },
+        {
+            code: [
+                "import {",
+                "a, ",
+                "b",
+                "} from 'module';"
+            ].join("\n"),
+            options: [{ ImportDeclaration: { multiline: true } }]
+        },
+        {
+            code: [
+                "import {",
+                " a,",
+                "} from 'module';"
+            ].join("\n"),
+            options: [{ ImportDeclaration: { consistent: true } }]
+        },
+        {
+            code: [
+                "import { a } from 'module';"
+            ].join("\n"),
+            options: [{ ImportDeclaration: { consistent: true } }]
+        },
+        {
+            code: [
+                "import {",
+                "a, b",
+                "} from 'module';"
+            ].join("\n"),
+            options: [{ ImportDeclaration: { minProperties: 2 } }]
+        },
+        {
+            code: [
+                "import {a, b} from 'module';"
+            ].join("\n"),
+            options: [{ ImportDeclaration: { minProperties: 3 } }]
+        },
+
+        // "ExportDeclaration" ---------------------------------------------
+        {
+            code: [
+                "export {a,",
+                "b};"
+            ].join("\n"),
+            options: [{ ExportDeclaration: "never" }]
+        },
+        {
+            code: [
+                "export {",
+                "a as a, b",
+                "} from 'module';"
+            ].join("\n"),
+            options: [{ ExportDeclaration: "always" }]
+        },
+        {
+            code: [
+                "export { a } from 'module';"
+            ].join("\n"),
+            options: [{ ExportDeclaration: { multiline: true } }]
+        },
+        {
+            code: [
+                "export {",
+                "a, ",
+                "b",
+                "} from 'module';"
+            ].join("\n"),
+            options: [{ ExportDeclaration: { multiline: true } }]
+        },
+        {
+            code: [
+                "export {a, ",
+                "b} from 'module';"
+            ].join("\n"),
+            options: [{ ExportDeclaration: { consistent: true } }]
+        },
+        {
+            code: [
+                "export {",
+                "a, b",
+                "} from 'module';"
+            ].join("\n"),
+            options: [{ ExportDeclaration: { minProperties: 2 } }]
+        },
+        {
+            code: [
+                "export {a, b} from 'module';"
+            ].join("\n"),
+            options: [{ ExportDeclaration: { minProperties: 3 } }]
         }
     ],
     invalid: [
@@ -1352,6 +1465,239 @@ ruleTester.run("object-curly-newline", rule, {
                 { line: 3, column: 5, message: "Expected a line break after this opening brace." },
                 { line: 3, column: 16, message: "Expected a line break before this closing brace." }
             ]
+        },
+
+        // "ImportDeclaration" ---------------------------------------------
+        {
+            code: [
+                "import {",
+                "    a,",
+                " b",
+                "} from 'module';"
+            ].join("\n"),
+            output: [
+                "import {a,",
+                " b} from 'module';"
+            ].join("\n"),
+            options: [{ ImportDeclaration: "never" }],
+            errors: [
+                { line: 1, column: 8, message: "Unexpected line break after this opening brace." },
+                { line: 4, column: 1, message: "Unexpected line break before this closing brace." }
+            ]
+        },
+        {
+            code: [
+                "import {a, b} from 'module';"
+            ].join("\n"),
+            output: [
+                "import {",
+                "a, b",
+                "} from 'module';"
+            ].join("\n"),
+            options: [{ ImportDeclaration: "always" }],
+            errors: [
+                { line: 1, column: 8, message: "Expected a line break after this opening brace." },
+                { line: 1, column: 13, message: "Expected a line break before this closing brace." }
+            ]
+        },
+        {
+            code: [
+                "import {a as c, b} from 'module';"
+            ].join("\n"),
+            output: [
+                "import {",
+                "a as c, b",
+                "} from 'module';"
+            ].join("\n"),
+            options: [{ ImportDeclaration: "always" }],
+            errors: [
+                { line: 1, column: 8, message: "Expected a line break after this opening brace." },
+                { line: 1, column: 18, message: "Expected a line break before this closing brace." }
+            ]
+        },
+        {
+            code: [
+                "import {a, ",
+                "b} from 'module';"
+            ].join("\n"),
+            output: [
+                "import {",
+                "a, ",
+                "b",
+                "} from 'module';"
+            ].join("\n"),
+            options: [{ ImportDeclaration: { multiline: true } }],
+            errors: [
+                { line: 1, column: 8, message: "Expected a line break after this opening brace." },
+                { line: 2, column: 2, message: "Expected a line break before this closing brace." }
+            ]
+        },
+        {
+            code: [
+                "import {a, ",
+                "b",
+                "} from 'module';"
+            ].join("\n"),
+            output: [
+                "import {a, ",
+                "b} from 'module';"
+            ].join("\n"),
+            options: [{ ImportDeclaration: { consistent: true } }],
+            errors: [
+                { line: 3, column: 1, message: "Unexpected line break before this closing brace." }
+            ]
+        },
+        {
+            code: [
+                "import {a, b",
+                "} from 'module';"
+            ].join("\n"),
+            output: [
+                "import {a, b} from 'module';"
+            ].join("\n"),
+            options: [{ ImportDeclaration: { consistent: true } }],
+            errors: [
+                { line: 2, column: 1, message: "Unexpected line break before this closing brace." }
+            ]
+        },
+        {
+            code: [
+                "import {a, b} from 'module';"
+            ].join("\n"),
+            output: [
+                "import {",
+                "a, b",
+                "} from 'module';"
+            ].join("\n"),
+            options: [{ ImportDeclaration: { minProperties: 2 } }],
+            errors: [
+                { line: 1, column: 8, message: "Expected a line break after this opening brace." },
+                { line: 1, column: 13, message: "Expected a line break before this closing brace." }
+            ]
+        },
+        {
+            code: [
+                "import {",
+                "a, b",
+                "} from 'module';"
+            ].join("\n"),
+            output: [
+                "import {a, b} from 'module';"
+            ].join("\n"),
+            options: [{ ImportDeclaration: { minProperties: 3 } }],
+            errors: [
+                { line: 1, column: 8, message: "Unexpected line break after this opening brace." },
+                { line: 3, column: 1, message: "Unexpected line break before this closing brace." }
+            ]
+        },
+
+        // "ExportDeclaration" ---------------------------------------------
+        {
+            code: [
+                "export {",
+                "    a,",
+                "    b",
+                "};"
+            ].join("\n"),
+            output: [
+                "export {a,",
+                "    b};"
+            ].join("\n"),
+            options: [{ ExportDeclaration: "never" }],
+            errors: [
+                { line: 1, column: 8, message: "Unexpected line break after this opening brace." },
+                { line: 4, column: 1, message: "Unexpected line break before this closing brace." }
+            ]
+        },
+        {
+            code: [
+                "export {a as a, b} from 'module';"
+            ].join("\n"),
+            output: [
+                "export {",
+                "a as a, b",
+                "} from 'module';"
+            ].join("\n"),
+            options: [{ ExportDeclaration: "always" }],
+            errors: [
+                { line: 1, column: 8, message: "Expected a line break after this opening brace." },
+                { line: 1, column: 18, message: "Expected a line break before this closing brace." }
+            ]
+        },
+        {
+            code: [
+                "export {a, ",
+                "b} from 'module';"
+            ].join("\n"),
+            output: [
+                "export {",
+                "a, ",
+                "b",
+                "} from 'module';"
+            ].join("\n"),
+            options: [{ ExportDeclaration: { multiline: true } }],
+            errors: [
+                { line: 1, column: 8, message: "Expected a line break after this opening brace." },
+                { line: 2, column: 2, message: "Expected a line break before this closing brace." }
+            ]
+        },
+        {
+            code: [
+                "export {a, ",
+                "b,",
+                "} from 'module';"
+            ].join("\n"),
+            output: [
+                "export {a, ",
+                "b,} from 'module';"
+            ].join("\n"),
+            options: [{ ExportDeclaration: { consistent: true } }],
+            errors: [
+                { line: 3, column: 1, message: "Unexpected line break before this closing brace." }
+            ]
+        },
+        {
+            code: [
+                "export {a, b",
+                "} from 'module';"
+            ].join("\n"),
+            output: [
+                "export {a, b} from 'module';"
+            ].join("\n"),
+            options: [{ ExportDeclaration: { consistent: true } }],
+            errors: [
+                { line: 2, column: 1, message: "Unexpected line break before this closing brace." }
+            ]
+        },
+        {
+            code: [
+                "export {a, b,} from 'module';"
+            ].join("\n"),
+            output: [
+                "export {",
+                "a, b,",
+                "} from 'module';"
+            ].join("\n"),
+            options: [{ ExportDeclaration: { minProperties: 2 } }],
+            errors: [
+                { line: 1, column: 8, message: "Expected a line break after this opening brace." },
+                { line: 1, column: 14, message: "Expected a line break before this closing brace." }
+            ]
+        },
+        {
+            code: [
+                "export {",
+                "a, b",
+                "} from 'module';"
+            ].join("\n"),
+            output: [
+                "export {a, b} from 'module';"
+            ].join("\n"),
+            options: [{ ExportDeclaration: { minProperties: 3 } }],
+            errors: [
+                { line: 1, column: 8, message: "Unexpected line break after this opening brace." },
+                { line: 3, column: 1, message: "Unexpected line break before this closing brace." }
+            ]
         }
     ]
 });
diff --git a/tests/lib/rules/object-property-newline.js b/tests/lib/rules/object-property-newline.js
index ed0e24db2..6a6a2616c 100644
--- a/tests/lib/rules/object-property-newline.js
+++ b/tests/lib/rules/object-property-newline.js
@@ -32,8 +32,11 @@ ruleTester.run("object-property-newline", rule, {
         "var obj = {};",
         { code: "var obj = {\n[bar]: 'baz',\nbaz\n};", parserOptions: { ecmaVersion: 6 } },
         { code: "var obj = {\nk1: 'val1',\nk2: 'val2',\n...{}\n};", parserOptions: { ecmaVersion: 6, ecmaFeatures: { experimentalObjectRestSpread: true } } },
+        { code: "var obj = {\nk1: 'val1',\nk2: 'val2',\n...{}\n};", parserOptions: { ecmaVersion: 2018 } },
         { code: "var obj = { k1: 'val1',\nk2: 'val2',\n...{} };", parserOptions: { ecmaVersion: 6, ecmaFeatures: { experimentalObjectRestSpread: true } } },
+        { code: "var obj = { k1: 'val1',\nk2: 'val2',\n...{} };", parserOptions: { ecmaVersion: 2018 } },
         { code: "var obj = { ...{} };", parserOptions: { ecmaVersion: 6, ecmaFeatures: { experimentalObjectRestSpread: true } } },
+        { code: "var obj = { ...{} };", parserOptions: { ecmaVersion: 2018 } },
         "foo({ k1: 'val1',\nk2: 'val2' });",
         "foo({\nk1: 'val1',\nk2: 'val2'\n});",
         { code: "foo({\na,\nb\n});", parserOptions: { ecmaVersion: 6 } },
@@ -41,8 +44,11 @@ ruleTester.run("object-property-newline", rule, {
         { code: "foo({\nbar() {},\nbaz\n});", parserOptions: { ecmaVersion: 6 } },
         { code: "foo({\n[bar]: 'baz',\nbaz \n})", parserOptions: { ecmaVersion: 6 } },
         { code: "foo({\nk1: 'val1',\nk2: 'val2',\n...{}\n});", parserOptions: { ecmaVersion: 6, ecmaFeatures: { experimentalObjectRestSpread: true } } },
+        { code: "foo({\nk1: 'val1',\nk2: 'val2',\n...{}\n});", parserOptions: { ecmaVersion: 2018 } },
         { code: "foo({ k1: 'val1',\nk2: 'val2',\n...{} });", parserOptions: { ecmaVersion: 6, ecmaFeatures: { experimentalObjectRestSpread: true } } },
+        { code: "foo({ k1: 'val1',\nk2: 'val2',\n...{} });", parserOptions: { ecmaVersion: 2018 } },
         { code: "foo({ ...{} });", parserOptions: { ecmaVersion: 6, ecmaFeatures: { experimentalObjectRestSpread: true } } },
+        { code: "foo({ ...{} });", parserOptions: { ecmaVersion: 2018 } },
 
         // allowAllPropertiesOnSameLine: true
         { code: "var obj = { k1: 'val1', k2: 'val2', k3: 'val3' };", options: [{ allowAllPropertiesOnSameLine: true }] },
@@ -51,14 +57,18 @@ ruleTester.run("object-property-newline", rule, {
         { code: "var obj = {\nk1: 'val1'\n};", options: [{ allowAllPropertiesOnSameLine: true }] },
         { code: "var obj = {};", options: [{ allowAllPropertiesOnSameLine: true }] },
         { code: "var obj = { 'k1': 'val1', k2: 'val2', ...{} };", options: [{ allowAllPropertiesOnSameLine: true }], parserOptions: { ecmaVersion: 6, ecmaFeatures: { experimentalObjectRestSpread: true } } },
+        { code: "var obj = { 'k1': 'val1', k2: 'val2', ...{} };", options: [{ allowAllPropertiesOnSameLine: true }], parserOptions: { ecmaVersion: 2018 } },
         { code: "var obj = {\n'k1': 'val1', k2: 'val2', ...{}\n};", options: [{ allowAllPropertiesOnSameLine: true }], parserOptions: { ecmaVersion: 6, ecmaFeatures: { experimentalObjectRestSpread: true } } },
+        { code: "var obj = {\n'k1': 'val1', k2: 'val2', ...{}\n};", options: [{ allowAllPropertiesOnSameLine: true }], parserOptions: { ecmaVersion: 2018 } },
         { code: "foo({ k1: 'val1', k2: 'val2' });", options: [{ allowAllPropertiesOnSameLine: true }] },
         { code: "foo({\nk1: 'val1', k2: 'val2'\n});", options: [{ allowAllPropertiesOnSameLine: true }] },
         { code: "foo({ a, b });", options: [{ allowAllPropertiesOnSameLine: true }], parserOptions: { ecmaVersion: 6 } },
         { code: "foo({ bar() {}, baz });", options: [{ allowAllPropertiesOnSameLine: true }], parserOptions: { ecmaVersion: 6 } },
         { code: "foo({ [bar]: 'baz', baz })", options: [{ allowAllPropertiesOnSameLine: true }], parserOptions: { ecmaVersion: 6 } },
         { code: "foo({ 'k1': 'val1', k2: 'val2', ...{} });", options: [{ allowAllPropertiesOnSameLine: true }], parserOptions: { ecmaVersion: 6, ecmaFeatures: { experimentalObjectRestSpread: true } } },
+        { code: "foo({ 'k1': 'val1', k2: 'val2', ...{} });", options: [{ allowAllPropertiesOnSameLine: true }], parserOptions: { ecmaVersion: 2018 } },
         { code: "foo({\n'k1': 'val1', k2: 'val2', ...{}\n});", options: [{ allowAllPropertiesOnSameLine: true }], parserOptions: { ecmaVersion: 6, ecmaFeatures: { experimentalObjectRestSpread: true } } },
+        { code: "foo({\n'k1': 'val1', k2: 'val2', ...{}\n});", options: [{ allowAllPropertiesOnSameLine: true }], parserOptions: { ecmaVersion: 2018 } },
         { code: "var obj = {k1: ['foo', 'bar'], k2: 'val1', k3: 'val2'};", options: [{ allowAllPropertiesOnSameLine: true }] },
         { code: "var obj = {\nk1: ['foo', 'bar'], k2: 'val1', k3: 'val2'\n};", options: [{ allowAllPropertiesOnSameLine: true }] },
         { code: "var obj = {\nk1: 'val1', k2: {e1: 'foo', e2: 'bar'}, k3: 'val2'\n};", options: [{ allowAllPropertiesOnSameLine: true }] },
@@ -216,6 +226,19 @@ ruleTester.run("object-property-newline", rule, {
                 }
             ]
         },
+        {
+            code: "var obj = { k1: 'val1', ...{} };",
+            output: "var obj = { k1: 'val1',\n...{} };",
+            parserOptions: { ecmaVersion: 2018 },
+            errors: [
+                {
+                    message: "Object properties must go on a new line.",
+                    type: "ObjectExpression",
+                    line: 1,
+                    column: 25
+                }
+            ]
+        },
         {
             code: "var obj = {\nk1: 'val1', ...{}\n};",
             output: "var obj = {\nk1: 'val1',\n...{}\n};",
@@ -229,6 +252,19 @@ ruleTester.run("object-property-newline", rule, {
                 }
             ]
         },
+        {
+            code: "var obj = {\nk1: 'val1', ...{}\n};",
+            output: "var obj = {\nk1: 'val1',\n...{}\n};",
+            parserOptions: { ecmaVersion: 2018 },
+            errors: [
+                {
+                    message: "Object properties must go on a new line.",
+                    type: "ObjectExpression",
+                    line: 2,
+                    column: 13
+                }
+            ]
+        },
         {
             code: "foo({ k1: 'val1', k2: 'val2' });",
             output: "foo({ k1: 'val1',\nk2: 'val2' });",
@@ -331,6 +367,19 @@ ruleTester.run("object-property-newline", rule, {
                 }
             ]
         },
+        {
+            code: "foo({ k1: 'val1', ...{} })",
+            output: "foo({ k1: 'val1',\n...{} })",
+            parserOptions: { ecmaVersion: 2018 },
+            errors: [
+                {
+                    message: "Object properties must go on a new line.",
+                    type: "ObjectExpression",
+                    line: 1,
+                    column: 19
+                }
+            ]
+        },
         {
             code: "foo({\nk1: 'val1', ...{}\n})",
             output: "foo({\nk1: 'val1',\n...{}\n})",
@@ -344,6 +393,19 @@ ruleTester.run("object-property-newline", rule, {
                 }
             ]
         },
+        {
+            code: "foo({\nk1: 'val1', ...{}\n})",
+            output: "foo({\nk1: 'val1',\n...{}\n})",
+            parserOptions: { ecmaVersion: 2018 },
+            errors: [
+                {
+                    message: "Object properties must go on a new line.",
+                    type: "ObjectExpression",
+                    line: 2,
+                    column: 13
+                }
+            ]
+        },
         {
             code: "var obj = {\na: {\nb: 1,\nc: 2\n}, d: 2\n};",
             output: "var obj = {\na: {\nb: 1,\nc: 2\n},\nd: 2\n};",
@@ -500,6 +562,20 @@ ruleTester.run("object-property-newline", rule, {
                 }
             ]
         },
+        {
+            code: "var obj = {\nk1: 'val1',\nk2: 'val2', ...{}\n};",
+            output: "var obj = {\nk1: 'val1',\nk2: 'val2',\n...{}\n};",
+            options: [{ allowAllPropertiesOnSameLine: true }],
+            parserOptions: { ecmaVersion: 2018 },
+            errors: [
+                {
+                    message: "Object properties must go on a new line if they aren't all on the same line.",
+                    type: "ObjectExpression",
+                    line: 3,
+                    column: 13
+                }
+            ]
+        },
         {
             code: "var obj = {\n...{},\nk1: 'val1', k2: 'val2'\n};",
             output: "var obj = {\n...{},\nk1: 'val1',\nk2: 'val2'\n};",
@@ -514,6 +590,20 @@ ruleTester.run("object-property-newline", rule, {
                 }
             ]
         },
+        {
+            code: "var obj = {\n...{},\nk1: 'val1', k2: 'val2'\n};",
+            output: "var obj = {\n...{},\nk1: 'val1',\nk2: 'val2'\n};",
+            options: [{ allowAllPropertiesOnSameLine: true }],
+            parserOptions: { ecmaVersion: 2018 },
+            errors: [
+                {
+                    message: "Object properties must go on a new line if they aren't all on the same line.",
+                    type: "ObjectExpression",
+                    line: 3,
+                    column: 13
+                }
+            ]
+        },
         {
             code: "foo({ [\nk1]: 'val1', k2: 'val2' })",
             output: "foo({ [\nk1]: 'val1',\nk2: 'val2' })",
@@ -542,6 +632,20 @@ ruleTester.run("object-property-newline", rule, {
                 }
             ]
         },
+        {
+            code: "foo({\nk1: 'val1',\nk2: 'val2', ...{}\n})",
+            output: "foo({\nk1: 'val1',\nk2: 'val2',\n...{}\n})",
+            options: [{ allowAllPropertiesOnSameLine: true }],
+            parserOptions: { ecmaVersion: 2018 },
+            errors: [
+                {
+                    message: "Object properties must go on a new line if they aren't all on the same line.",
+                    type: "ObjectExpression",
+                    line: 3,
+                    column: 13
+                }
+            ]
+        },
         {
             code: "foo({\n...{},\nk1: 'val1', k2: 'val2'\n})",
             output: "foo({\n...{},\nk1: 'val1',\nk2: 'val2'\n})",
@@ -556,6 +660,20 @@ ruleTester.run("object-property-newline", rule, {
                 }
             ]
         },
+        {
+            code: "foo({\n...{},\nk1: 'val1', k2: 'val2'\n})",
+            output: "foo({\n...{},\nk1: 'val1',\nk2: 'val2'\n})",
+            options: [{ allowAllPropertiesOnSameLine: true }],
+            parserOptions: { ecmaVersion: 2018 },
+            errors: [
+                {
+                    message: "Object properties must go on a new line if they aren't all on the same line.",
+                    type: "ObjectExpression",
+                    line: 3,
+                    column: 13
+                }
+            ]
+        },
 
         // allowMultiplePropertiesPerLine: true (deprecated)
         {
diff --git a/tests/lib/rules/object-shorthand.js b/tests/lib/rules/object-shorthand.js
index 0606d0ed8..e0b30b992 100644
--- a/tests/lib/rules/object-shorthand.js
+++ b/tests/lib/rules/object-shorthand.js
@@ -24,7 +24,7 @@ const LONGFORM_METHOD_STRING_LITERAL_ERROR = { message: "Expected longform metho
 const ALL_SHORTHAND_ERROR = { message: "Expected shorthand for all properties.", type: "ObjectExpression" };
 const MIXED_SHORTHAND_ERROR = { message: "Unexpected mix of shorthand and non-shorthand properties.", type: "ObjectExpression" };
 
-const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } });
+const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 2018 } });
 
 ruleTester.run("object-shorthand", rule, {
     valid: [
@@ -176,6 +176,11 @@ ruleTester.run("object-shorthand", rule, {
             options: ["never"],
             parserOptions: { ecmaFeatures: { experimentalObjectRestSpread: true } }
         },
+        {
+            code: "var x = {foo: foo, bar: bar, ...baz}",
+            options: ["never"],
+            parserOptions: { ecmaVersion: 2018 }
+        },
 
         // consistent
         {
@@ -199,21 +204,41 @@ ruleTester.run("object-shorthand", rule, {
             options: ["consistent-as-needed"],
             parserOptions: { ecmaFeatures: { experimentalObjectRestSpread: true } }
         },
+        {
+            code: "var x = {...bar}",
+            options: ["consistent-as-needed"],
+            parserOptions: { ecmaVersion: 2018 }
+        },
         {
             code: "var x = {foo, bar, ...baz}",
             options: ["consistent"],
             parserOptions: { ecmaFeatures: { experimentalObjectRestSpread: true } }
         },
+        {
+            code: "var x = {foo, bar, ...baz}",
+            options: ["consistent"],
+            parserOptions: { ecmaVersion: 2018 }
+        },
         {
             code: "var x = {bar: baz, ...qux}",
             options: ["consistent"],
             parserOptions: { ecmaFeatures: { experimentalObjectRestSpread: true } }
         },
+        {
+            code: "var x = {bar: baz, ...qux}",
+            options: ["consistent"],
+            parserOptions: { ecmaVersion: 2018 }
+        },
         {
             code: "var x = {...foo, bar: bar, baz: baz}",
             options: ["consistent"],
             parserOptions: { ecmaFeatures: { experimentalObjectRestSpread: true } }
         },
+        {
+            code: "var x = {...foo, bar: bar, baz: baz}",
+            options: ["consistent"],
+            parserOptions: { ecmaVersion: 2018 }
+        },
 
         // consistent-as-needed
         {
@@ -253,16 +278,31 @@ ruleTester.run("object-shorthand", rule, {
             options: ["consistent-as-needed"],
             parserOptions: { ecmaFeatures: { experimentalObjectRestSpread: true } }
         },
+        {
+            code: "var x = {bar, ...baz}",
+            options: ["consistent-as-needed"],
+            parserOptions: { ecmaVersion: 2018 }
+        },
         {
             code: "var x = {bar: baz, ...qux}",
             options: ["consistent-as-needed"],
             parserOptions: { ecmaFeatures: { experimentalObjectRestSpread: true } }
         },
+        {
+            code: "var x = {bar: baz, ...qux}",
+            options: ["consistent-as-needed"],
+            parserOptions: { ecmaVersion: 2018 }
+        },
         {
             code: "var x = {...foo, bar, baz}",
             options: ["consistent-as-needed"],
             parserOptions: { ecmaFeatures: { experimentalObjectRestSpread: true } }
         },
+        {
+            code: "var x = {...foo, bar, baz}",
+            options: ["consistent-as-needed"],
+            parserOptions: { ecmaVersion: 2018 }
+        },
 
         // avoidExplicitReturnArrows
         {
@@ -690,6 +730,13 @@ ruleTester.run("object-shorthand", rule, {
             parserOptions: { ecmaFeatures: { experimentalObjectRestSpread: true } },
             errors: [PROPERTY_ERROR]
         },
+        {
+            code: "var x = {foo: foo, bar: baz, ...qux}",
+            output: "var x = {foo, bar: baz, ...qux}",
+            options: ["always"],
+            parserOptions: { ecmaVersion: 2018 },
+            errors: [PROPERTY_ERROR]
+        },
         {
             code: "var x = {foo, bar: baz, ...qux}",
             output: "var x = {foo: foo, bar: baz, ...qux}",
@@ -697,6 +744,13 @@ ruleTester.run("object-shorthand", rule, {
             parserOptions: { ecmaFeatures: { experimentalObjectRestSpread: true } },
             errors: [LONGFORM_PROPERTY_ERROR]
         },
+        {
+            code: "var x = {foo, bar: baz, ...qux}",
+            output: "var x = {foo: foo, bar: baz, ...qux}",
+            options: ["never"],
+            parserOptions: { ecmaVersion: 2018 },
+            errors: [LONGFORM_PROPERTY_ERROR]
+        },
 
         // avoidQuotes
         {
@@ -750,6 +804,13 @@ ruleTester.run("object-shorthand", rule, {
             parserOptions: { ecmaFeatures: { experimentalObjectRestSpread: true } },
             errors: [MIXED_SHORTHAND_ERROR]
         },
+        {
+            code: "var x = {foo, bar: baz, ...qux}",
+            output: null,
+            options: ["consistent"],
+            parserOptions: { ecmaVersion: 2018 },
+            errors: [MIXED_SHORTHAND_ERROR]
+        },
 
         // consistent-as-needed
         {
@@ -778,6 +839,13 @@ ruleTester.run("object-shorthand", rule, {
             parserOptions: { ecmaFeatures: { experimentalObjectRestSpread: true } },
             errors: [ALL_SHORTHAND_ERROR]
         },
+        {
+            code: "var x = {a: a, b: b, ...baz}",
+            output: null,
+            options: ["consistent-as-needed"],
+            parserOptions: { ecmaVersion: 2018 },
+            errors: [ALL_SHORTHAND_ERROR]
+        },
         {
             code: "var x = {foo, bar: bar, ...qux}",
             output: null,
@@ -785,6 +853,13 @@ ruleTester.run("object-shorthand", rule, {
             parserOptions: { ecmaFeatures: { experimentalObjectRestSpread: true } },
             errors: [MIXED_SHORTHAND_ERROR]
         },
+        {
+            code: "var x = {foo, bar: bar, ...qux}",
+            output: null,
+            options: ["consistent-as-needed"],
+            parserOptions: { ecmaVersion: 2018 },
+            errors: [MIXED_SHORTHAND_ERROR]
+        },
 
         // avoidExplicitReturnArrows
         {
@@ -979,6 +1054,20 @@ ruleTester.run("object-shorthand", rule, {
             output: "({ a() { return foo; } })",
             options: ["always", { avoidExplicitReturnArrows: true }],
             errors: [METHOD_ERROR]
+        },
+
+        // async generators
+        {
+            code: "({ a: async function*() {} })",
+            output: "({ async *a() {} })",
+            options: ["always"],
+            errors: [METHOD_ERROR]
+        },
+        {
+            code: "({ async* a() {} })",
+            output: "({ a: async function*() {} })",
+            options: ["never"],
+            errors: [LONGFORM_METHOD_ERROR]
         }
     ]
 });
diff --git a/tests/lib/rules/prefer-const.js b/tests/lib/rules/prefer-const.js
index 31dceb45a..a86335c0d 100644
--- a/tests/lib/rules/prefer-const.js
+++ b/tests/lib/rules/prefer-const.js
@@ -95,6 +95,11 @@ ruleTester.run("prefer-const", rule, {
             options: [{ destructuring: "all" }],
             parserOptions: { ecmaFeatures: { experimentalObjectRestSpread: true } }
         },
+        {
+            code: "let { name, ...otherStuff } = obj; otherStuff = {};",
+            options: [{ destructuring: "all" }],
+            parserOptions: { ecmaVersion: 2018 }
+        },
         {
             code: "let { name, ...otherStuff } = obj; otherStuff = {};",
             options: [{ destructuring: "all" }],
@@ -311,6 +316,13 @@ ruleTester.run("prefer-const", rule, {
             parserOptions: { ecmaFeatures: { experimentalObjectRestSpread: true } },
             errors: [{ message: "'name' is never reassigned. Use 'const' instead.", type: "Identifier", column: 7 }]
         },
+        {
+            code: "let { name, ...otherStuff } = obj; otherStuff = {};",
+            output: null,
+            options: [{ destructuring: "any" }],
+            parserOptions: { ecmaVersion: 2018 },
+            errors: [{ message: "'name' is never reassigned. Use 'const' instead.", type: "Identifier", column: 7 }]
+        },
         {
             code: "let { name, ...otherStuff } = obj; otherStuff = {};",
             output: null,
diff --git a/tests/lib/rules/quote-props.js b/tests/lib/rules/quote-props.js
index 3ff23b7ee..9c87da607 100644
--- a/tests/lib/rules/quote-props.js
+++ b/tests/lib/rules/quote-props.js
@@ -72,8 +72,11 @@ ruleTester.run("quote-props", rule, {
         { code: "({1: 1, x: 2})", options: ["consistent", { numbers: true }] },
         { code: "({1: 1, x: 2})", options: ["consistent-as-needed", { numbers: true }] },
         { code: "({ ...x })", options: ["as-needed"], parserOptions: { ecmaVersion: 6, ecmaFeatures: { experimentalObjectRestSpread: true } } },
+        { code: "({ ...x })", options: ["as-needed"], parserOptions: { ecmaVersion: 2018 } },
         { code: "({ ...x })", options: ["consistent"], parserOptions: { ecmaVersion: 6, ecmaFeatures: { experimentalObjectRestSpread: true } } },
-        { code: "({ ...x })", options: ["consistent-as-needed"], parserOptions: { ecmaVersion: 6, ecmaFeatures: { experimentalObjectRestSpread: true } } }
+        { code: "({ ...x })", options: ["consistent"], parserOptions: { ecmaVersion: 2018 } },
+        { code: "({ ...x })", options: ["consistent-as-needed"], parserOptions: { ecmaVersion: 6, ecmaFeatures: { experimentalObjectRestSpread: true } } },
+        { code: "({ ...x })", options: ["consistent-as-needed"], parserOptions: { ecmaVersion: 2018 } }
     ],
     invalid: [{
         code: "({ a: 0 })",
diff --git a/tests/lib/rules/require-await.js b/tests/lib/rules/require-await.js
index 6248ac8a5..662dc72cb 100644
--- a/tests/lib/rules/require-await.js
+++ b/tests/lib/rules/require-await.js
@@ -18,7 +18,7 @@ const rule = require("../../../lib/rules/require-await"),
 
 const ruleTester = new RuleTester({
     parserOptions: {
-        ecmaVersion: 2017
+        ecmaVersion: 2018
     }
 });
 
@@ -38,7 +38,10 @@ ruleTester.run("require-await", rule, {
         "async () => {}",
 
         // normal functions are ok.
-        "function foo() { doSomething() }"
+        "function foo() { doSomething() }",
+
+        // for-await-of
+        "async function foo() { for await (x of xs); }"
     ],
     invalid: [
         {
diff --git a/tests/lib/rules/rest-spread-spacing.js b/tests/lib/rules/rest-spread-spacing.js
index d78499d3d..c7f28aa4a 100644
--- a/tests/lib/rules/rest-spread-spacing.js
+++ b/tests/lib/rules/rest-spread-spacing.js
@@ -36,17 +36,29 @@ ruleTester.run("rest-spread-spacing", rule, {
         { code: "let [a, b, ...\tarr] = [1, 2, 3, 4, 5];", options: ["always"] },
         { code: "let [a, b, ...\narr] = [1, 2, 3, 4, 5];", options: ["always"] },
         { code: "let n = { x, y, ...z };", parserOptions: { ecmaFeatures: { experimentalObjectRestSpread: true } } },
+        { code: "let n = { x, y, ...z };", parserOptions: { ecmaVersion: 2018 } },
         { code: "let n = { x, y, ...(z) };", parserOptions: { ecmaFeatures: { experimentalObjectRestSpread: true } } },
+        { code: "let n = { x, y, ...(z) };", parserOptions: { ecmaVersion: 2018 } },
         { code: "let n = { x, y, ...( z ) };", parserOptions: { ecmaFeatures: { experimentalObjectRestSpread: true } } },
+        { code: "let n = { x, y, ...( z ) };", parserOptions: { ecmaVersion: 2018 } },
         { code: "let n = { x, y, ...z };", options: ["never"], parserOptions: { ecmaFeatures: { experimentalObjectRestSpread: true } } },
+        { code: "let n = { x, y, ...z };", options: ["never"], parserOptions: { ecmaVersion: 2018 } },
         { code: "let n = { x, y, ... z };", options: ["always"], parserOptions: { ecmaFeatures: { experimentalObjectRestSpread: true } } },
+        { code: "let n = { x, y, ... z };", options: ["always"], parserOptions: { ecmaVersion: 2018 } },
         { code: "let n = { x, y, ...\tz };", options: ["always"], parserOptions: { ecmaFeatures: { experimentalObjectRestSpread: true } } },
+        { code: "let n = { x, y, ...\tz };", options: ["always"], parserOptions: { ecmaVersion: 2018 } },
         { code: "let n = { x, y, ...\nz };", options: ["always"], parserOptions: { ecmaFeatures: { experimentalObjectRestSpread: true } } },
+        { code: "let n = { x, y, ...\nz };", options: ["always"], parserOptions: { ecmaVersion: 2018 } },
         { code: "let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };", parserOptions: { ecmaFeatures: { experimentalObjectRestSpread: true } } },
+        { code: "let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };", parserOptions: { ecmaVersion: 2018 } },
         { code: "let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };", options: ["never"], parserOptions: { ecmaFeatures: { experimentalObjectRestSpread: true } } },
+        { code: "let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };", options: ["never"], parserOptions: { ecmaVersion: 2018 } },
         { code: "let { x, y, ... z } = { x: 1, y: 2, a: 3, b: 4 };", options: ["always"], parserOptions: { ecmaFeatures: { experimentalObjectRestSpread: true } } },
+        { code: "let { x, y, ... z } = { x: 1, y: 2, a: 3, b: 4 };", options: ["always"], parserOptions: { ecmaVersion: 2018 } },
         { code: "let { x, y, ...\tz } = { x: 1, y: 2, a: 3, b: 4 };", options: ["always"], parserOptions: { ecmaFeatures: { experimentalObjectRestSpread: true } } },
-        { code: "let { x, y, ...\nz } = { x: 1, y: 2, a: 3, b: 4 };", options: ["always"], parserOptions: { ecmaFeatures: { experimentalObjectRestSpread: true } } }
+        { code: "let { x, y, ...\tz } = { x: 1, y: 2, a: 3, b: 4 };", options: ["always"], parserOptions: { ecmaVersion: 2018 } },
+        { code: "let { x, y, ...\nz } = { x: 1, y: 2, a: 3, b: 4 };", options: ["always"], parserOptions: { ecmaFeatures: { experimentalObjectRestSpread: true } } },
+        { code: "let { x, y, ...\nz } = { x: 1, y: 2, a: 3, b: 4 };", options: ["always"], parserOptions: { ecmaVersion: 2018 } }
     ],
 
     invalid: [
@@ -367,6 +379,17 @@ ruleTester.run("rest-spread-spacing", rule, {
                 type: "ExperimentalSpreadProperty"
             }]
         },
+        {
+            code: "let n = { x, y, ... z };",
+            output: "let n = { x, y, ...z };",
+            parserOptions: { ecmaVersion: 2018 },
+            errors: [{
+                line: 1,
+                column: 20,
+                message: "Unexpected whitespace after spread property operator.",
+                type: "SpreadElement"
+            }]
+        },
         {
             code: "let n = { x, y, ...\tz };",
             output: "let n = { x, y, ...z };",
@@ -378,6 +401,17 @@ ruleTester.run("rest-spread-spacing", rule, {
                 type: "ExperimentalSpreadProperty"
             }]
         },
+        {
+            code: "let n = { x, y, ...\tz };",
+            output: "let n = { x, y, ...z };",
+            parserOptions: { ecmaVersion: 2018 },
+            errors: [{
+                line: 1,
+                column: 20,
+                message: "Unexpected whitespace after spread property operator.",
+                type: "SpreadElement"
+            }]
+        },
         {
             code: "let n = { x, y, ...\nz };",
             output: "let n = { x, y, ...z };",
@@ -389,6 +423,17 @@ ruleTester.run("rest-spread-spacing", rule, {
                 type: "ExperimentalSpreadProperty"
             }]
         },
+        {
+            code: "let n = { x, y, ...\nz };",
+            output: "let n = { x, y, ...z };",
+            parserOptions: { ecmaVersion: 2018 },
+            errors: [{
+                line: 1,
+                column: 20,
+                message: "Unexpected whitespace after spread property operator.",
+                type: "SpreadElement"
+            }]
+        },
         {
             code: "let n = { x, y, ... z };",
             output: "let n = { x, y, ...z };",
@@ -401,6 +446,18 @@ ruleTester.run("rest-spread-spacing", rule, {
                 type: "ExperimentalSpreadProperty"
             }]
         },
+        {
+            code: "let n = { x, y, ... z };",
+            output: "let n = { x, y, ...z };",
+            options: ["never"],
+            parserOptions: { ecmaVersion: 2018 },
+            errors: [{
+                line: 1,
+                column: 20,
+                message: "Unexpected whitespace after spread property operator.",
+                type: "SpreadElement"
+            }]
+        },
         {
             code: "let n = { x, y, ...\tz };",
             output: "let n = { x, y, ...z };",
@@ -413,6 +470,18 @@ ruleTester.run("rest-spread-spacing", rule, {
                 type: "ExperimentalSpreadProperty"
             }]
         },
+        {
+            code: "let n = { x, y, ...\tz };",
+            output: "let n = { x, y, ...z };",
+            options: ["never"],
+            parserOptions: { ecmaVersion: 2018 },
+            errors: [{
+                line: 1,
+                column: 20,
+                message: "Unexpected whitespace after spread property operator.",
+                type: "SpreadElement"
+            }]
+        },
         {
             code: "let n = { x, y, ...\nz };",
             output: "let n = { x, y, ...z };",
@@ -425,6 +494,18 @@ ruleTester.run("rest-spread-spacing", rule, {
                 type: "ExperimentalSpreadProperty"
             }]
         },
+        {
+            code: "let n = { x, y, ...\nz };",
+            output: "let n = { x, y, ...z };",
+            options: ["never"],
+            parserOptions: { ecmaVersion: 2018 },
+            errors: [{
+                line: 1,
+                column: 20,
+                message: "Unexpected whitespace after spread property operator.",
+                type: "SpreadElement"
+            }]
+        },
         {
             code: "let n = { x, y, ...z };",
             output: "let n = { x, y, ... z };",
@@ -437,6 +518,18 @@ ruleTester.run("rest-spread-spacing", rule, {
                 type: "ExperimentalSpreadProperty"
             }]
         },
+        {
+            code: "let n = { x, y, ...z };",
+            output: "let n = { x, y, ... z };",
+            options: ["always"],
+            parserOptions: { ecmaVersion: 2018 },
+            errors: [{
+                line: 1,
+                column: 20,
+                message: "Expected whitespace after spread property operator.",
+                type: "SpreadElement"
+            }]
+        },
         {
             code: "let n = { x, y, ... (z) };",
             output: "let n = { x, y, ...(z) };",
@@ -449,6 +542,18 @@ ruleTester.run("rest-spread-spacing", rule, {
                 type: "ExperimentalSpreadProperty"
             }]
         },
+        {
+            code: "let n = { x, y, ... (z) };",
+            output: "let n = { x, y, ...(z) };",
+            options: ["never"],
+            parserOptions: { ecmaVersion: 2018 },
+            errors: [{
+                line: 1,
+                column: 20,
+                message: "Unexpected whitespace after spread property operator.",
+                type: "SpreadElement"
+            }]
+        },
         {
             code: "let n = { x, y, ... ( z ) };",
             output: "let n = { x, y, ...( z ) };",
@@ -461,6 +566,18 @@ ruleTester.run("rest-spread-spacing", rule, {
                 type: "ExperimentalSpreadProperty"
             }]
         },
+        {
+            code: "let n = { x, y, ... ( z ) };",
+            output: "let n = { x, y, ...( z ) };",
+            options: ["never"],
+            parserOptions: { ecmaVersion: 2018 },
+            errors: [{
+                line: 1,
+                column: 20,
+                message: "Unexpected whitespace after spread property operator.",
+                type: "SpreadElement"
+            }]
+        },
         {
             code: "let n = { x, y, ...(z) };",
             output: "let n = { x, y, ... (z) };",
@@ -473,6 +590,18 @@ ruleTester.run("rest-spread-spacing", rule, {
                 type: "ExperimentalSpreadProperty"
             }]
         },
+        {
+            code: "let n = { x, y, ...(z) };",
+            output: "let n = { x, y, ... (z) };",
+            options: ["always"],
+            parserOptions: { ecmaVersion: 2018 },
+            errors: [{
+                line: 1,
+                column: 20,
+                message: "Expected whitespace after spread property operator.",
+                type: "SpreadElement"
+            }]
+        },
         {
             code: "let n = { x, y, ...( z ) };",
             output: "let n = { x, y, ... ( z ) };",
@@ -485,6 +614,18 @@ ruleTester.run("rest-spread-spacing", rule, {
                 type: "ExperimentalSpreadProperty"
             }]
         },
+        {
+            code: "let n = { x, y, ...( z ) };",
+            output: "let n = { x, y, ... ( z ) };",
+            options: ["always"],
+            parserOptions: { ecmaVersion: 2018 },
+            errors: [{
+                line: 1,
+                column: 20,
+                message: "Expected whitespace after spread property operator.",
+                type: "SpreadElement"
+            }]
+        },
         {
             code: "let { x, y, ... z } = { x: 1, y: 2, a: 3, b: 4 };",
             output: "let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };",
@@ -496,6 +637,17 @@ ruleTester.run("rest-spread-spacing", rule, {
                 type: "ExperimentalRestProperty"
             }]
         },
+        {
+            code: "let { x, y, ... z } = { x: 1, y: 2, a: 3, b: 4 };",
+            output: "let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };",
+            parserOptions: { ecmaVersion: 2018 },
+            errors: [{
+                line: 1,
+                column: 16,
+                message: "Unexpected whitespace after rest property operator.",
+                type: "RestElement"
+            }]
+        },
         {
             code: "let { x, y, ...\tz } = { x: 1, y: 2, a: 3, b: 4 };",
             output: "let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };",
@@ -507,6 +659,17 @@ ruleTester.run("rest-spread-spacing", rule, {
                 type: "ExperimentalRestProperty"
             }]
         },
+        {
+            code: "let { x, y, ...\tz } = { x: 1, y: 2, a: 3, b: 4 };",
+            output: "let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };",
+            parserOptions: { ecmaVersion: 2018 },
+            errors: [{
+                line: 1,
+                column: 16,
+                message: "Unexpected whitespace after rest property operator.",
+                type: "RestElement"
+            }]
+        },
         {
             code: "let { x, y, ...\nz } = { x: 1, y: 2, a: 3, b: 4 };",
             output: "let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };",
@@ -518,6 +681,17 @@ ruleTester.run("rest-spread-spacing", rule, {
                 type: "ExperimentalRestProperty"
             }]
         },
+        {
+            code: "let { x, y, ...\nz } = { x: 1, y: 2, a: 3, b: 4 };",
+            output: "let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };",
+            parserOptions: { ecmaVersion: 2018 },
+            errors: [{
+                line: 1,
+                column: 16,
+                message: "Unexpected whitespace after rest property operator.",
+                type: "RestElement"
+            }]
+        },
         {
             code: "let { x, y, ... z } = { x: 1, y: 2, a: 3, b: 4 };",
             output: "let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };",
@@ -530,6 +704,18 @@ ruleTester.run("rest-spread-spacing", rule, {
                 type: "ExperimentalRestProperty"
             }]
         },
+        {
+            code: "let { x, y, ... z } = { x: 1, y: 2, a: 3, b: 4 };",
+            output: "let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };",
+            options: ["never"],
+            parserOptions: { ecmaVersion: 2018 },
+            errors: [{
+                line: 1,
+                column: 16,
+                message: "Unexpected whitespace after rest property operator.",
+                type: "RestElement"
+            }]
+        },
         {
             code: "let { x, y, ...\tz } = { x: 1, y: 2, a: 3, b: 4 };",
             output: "let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };",
@@ -542,6 +728,18 @@ ruleTester.run("rest-spread-spacing", rule, {
                 type: "ExperimentalRestProperty"
             }]
         },
+        {
+            code: "let { x, y, ...\tz } = { x: 1, y: 2, a: 3, b: 4 };",
+            output: "let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };",
+            options: ["never"],
+            parserOptions: { ecmaVersion: 2018 },
+            errors: [{
+                line: 1,
+                column: 16,
+                message: "Unexpected whitespace after rest property operator.",
+                type: "RestElement"
+            }]
+        },
         {
             code: "let { x, y, ...\nz } = { x: 1, y: 2, a: 3, b: 4 };",
             output: "let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };",
@@ -554,6 +752,18 @@ ruleTester.run("rest-spread-spacing", rule, {
                 type: "ExperimentalRestProperty"
             }]
         },
+        {
+            code: "let { x, y, ...\nz } = { x: 1, y: 2, a: 3, b: 4 };",
+            output: "let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };",
+            options: ["never"],
+            parserOptions: { ecmaVersion: 2018 },
+            errors: [{
+                line: 1,
+                column: 16,
+                message: "Unexpected whitespace after rest property operator.",
+                type: "RestElement"
+            }]
+        },
         {
             code: "let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };",
             output: "let { x, y, ... z } = { x: 1, y: 2, a: 3, b: 4 };",
@@ -565,6 +775,18 @@ ruleTester.run("rest-spread-spacing", rule, {
                 message: "Expected whitespace after rest property operator.",
                 type: "ExperimentalRestProperty"
             }]
+        },
+        {
+            code: "let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };",
+            output: "let { x, y, ... z } = { x: 1, y: 2, a: 3, b: 4 };",
+            options: ["always"],
+            parserOptions: { ecmaVersion: 2018 },
+            errors: [{
+                line: 1,
+                column: 16,
+                message: "Expected whitespace after rest property operator.",
+                type: "RestElement"
+            }]
         }
     ]
 });
diff --git a/tests/lib/rules/sort-keys.js b/tests/lib/rules/sort-keys.js
index 82fbb42fb..2a94850a0 100644
--- a/tests/lib/rules/sort-keys.js
+++ b/tests/lib/rules/sort-keys.js
@@ -35,6 +35,7 @@ ruleTester.run("sort-keys", rule, {
 
         // ignore spread properties.
         { code: "var obj = {a:1, ...z, b:1}", options: [], parserOptions: { ecmaVersion: 6, ecmaFeatures: { experimentalObjectRestSpread: true } } },
+        { code: "var obj = {a:1, ...z, b:1}", options: [], parserOptions: { ecmaVersion: 2018 } },
 
         // ignore destructuring patterns.
         { code: "let {a, b} = {}", options: [], parserOptions: { ecmaVersion: 6 } },
@@ -168,6 +169,15 @@ ruleTester.run("sort-keys", rule, {
                 "Expected object keys to be in ascending order. 'a' should be before 'b'."
             ]
         },
+        {
+            code: "var obj = {b:1, ...z, a:1}",
+            parserOptions: {
+                ecmaVersion: 2018
+            },
+            errors: [
+                "Expected object keys to be in ascending order. 'a' should be before 'b'."
+            ]
+        },
 
         // nested
         {