Repository: eslint/eslint
Pull request #10677 (2018-07-26 05:42:21)

Chore: use eslintrc overrides
<!--
    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)**
similar to https://github.com/eslint/eslint/pull/10566

**Is there anything you'd like reviewers to focus on?**
no




Patch:
diff --git a/.eslintignore b/.eslintignore
index 59229ab0f..e9b3570d8 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -7,5 +7,6 @@
 /tests/fixtures/**
 /tests/performance/**
 /tmp/**
+/lib/util/unicode/is-combining-character.js
 test.js
 !.eslintrc.js
diff --git a/.eslintrc.js b/.eslintrc.js
index 71f801a84..df7f3951d 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -28,6 +28,17 @@ module.exports = {
     },
     overrides: [
         {
+            files: ["lib/rules/*", "tools/internal-rules/*"],
+            rules: {
+                "rulesdir/no-invalid-meta": "error",
+                "rulesdir/consistent-docs-description": "error"
+            }
+        }, {
+            files: ["lib/rules/*"],
+            rules: {
+                "rulesdir/consistent-docs-url": "error"
+            }
+        }, {
             files: ["tests/**/*"],
             env: { mocha: true },
             rules: {
diff --git a/.gitattributes b/.gitattributes
index 797b96ff6..1df258761 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1,4 +1,8 @@
 # Convert text file line endings to lf
 * text=auto
 
-*.js    text eol=lf
+*.js text eol=lf
+
+# The test fixtures are text files.
+/tests/fixtures/**/* text eol=lf
+/tests/fixtures/ignored-paths/crlf/.eslintignore text eol=crlf
diff --git a/CHANGELOG.md b/CHANGELOG.md
index bd7150ed2..8dd298afc 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,37 @@
+v5.3.0 - August 3, 2018
+
+* dd6cb19 Docs: Updated no-return-await Rule Documentation (fixes #9695) (#10699) (Marla Foreman)
+* 6009239 Chore: rename utils for consistency (#10727) (薛定谔的猫)
+* 6eb972c New: require-unicode-regexp rule (fixes #9961) (#10698) (Toru Nagashima)
+* 5c5d64d Fix: ignored-paths for Windows path (fixes #10687) (#10691) (Toru Nagashima)
+* 5f6a765 Build: ensure URL fragments remain in documentation links (fixes #10717) (#10720) (Teddy Katz)
+* 863aa78 Docs: add another example for when not to use no-await-in-loop (#10714) (Valeri Karpov)
+* 6e78b7d Docs: remove links to terminated jscs.info domain (#10706) (Piotr Kuczynski)
+* d56c39d Fix: ESLint cache no longer stops autofix (fixes #10679) (#10694) (Kevin Partington)
+* 2cc3240 New: add no-misleading-character-class (fixes #10049) (#10511) (Toru Nagashima)
+* 877f4b8 Fix: The "../.." folder is always ignored (fixes #10675) (#10682) (Sridhar)
+* 5984820 Chore: Move lib/file-finder.js to lib/util/ (refs #10559) (#10695) (Kevin Partington)
+* e37a593 Update: Fix incorrect default value for position (#10670) (Iulian Onofrei)
+* 8084bfc Docs: change when not to use object spread (#10621) (Benny Powers)
+* 7f496e2 Chore: Update require path for ast-utils (#10693) (Kevin Partington)
+* 648a33a Chore: reorganize code structure of utilities (refs #10599) (#10680) (薛定谔的猫)
+* f026fe1 Update: Fix 'function' in padding-line-between-statements (fixes #10487) (#10676) (Kevin Partington)
+* c2bb8bb Docs: Remove superfluous object option sample code (#10652) (Iulian Onofrei)
+* d34a13b Docs: add subheader in configuring/configuring-rules (#10686) (薛定谔的猫)
+* d8aea28 Chore: rm unnecessary plugin in eslint-config-eslint (#10685) (薛定谔的猫)
+* 9e76be7 Update: indent comments w/ nearby code if no blank lines (fixes #9733) (#10640) (Kevin Partington)
+* 9e93d46 New: add no-async-promise-executor rule (fixes #10217) (#10661) (Teddy Katz)
+* 5a2538c New: require-atomic-updates rule (fixes #10405) (#10655) (Teddy Katz)
+* 8b83d2b Fix: always resolve default ignore patterns from CWD (fixes #9227) (#10638) (Teddy Katz)
+* acb6658 Fix: ESLint crash with prefer-object-spread (fixes #10646) (#10649) (薛定谔的猫)
+* 99fb7d3 Docs: fix misleading no-prototype-builtins description (#10666) (薛定谔的猫)
+* 005b849 Docs: fix outdated description of `baseConfig` option (#10657) (Teddy Katz)
+* 15a77c4 Docs: fix broken links (fixes eslint/eslint-jp#6) (#10658) (Toru Nagashima)
+* 87cd344 Docs: Make marking a default option consistent with other rules (#10650) (Iulian Onofrei)
+* 0cb5e3e Chore: Replace some function application with spread operators (#10645) (Kevin Partington)
+* b6daf0e Docs: Remove superfluous section from no-unsafe-negation (#10648) (Iulian Onofrei)
+* e1a3cac Chore: rm deprecated experimentalObjectRestSpread option in tests (#10647) (薛定谔的猫)
+
 v5.2.0 - July 20, 2018
 
 * 81283d0 Update: Cache files that failed linting (fixes #9948) (#10571) (Kevin Partington)
diff --git a/Makefile.js b/Makefile.js
index cd756a746..902ee5857 100644
--- a/Makefile.js
+++ b/Makefile.js
@@ -745,7 +745,7 @@ target.gensite = function(prereleaseVersion) {
             ].join("\n");
 
             // 6. Remove .md extension for relative links and change README to empty string
-            text = text.replace(/\((?!https?:\/\/)([^)]*?)\.md.*?\)/g, "($1)").replace("README.html", "");
+            text = text.replace(/\((?!https?:\/\/)([^)]*?)\.md(.*?)\)/g, "($1$2)").replace("README.html", "");
 
             // 7. Check if there's a trailing white line at the end of the file, if there isn't one, add it
             if (!/\n$/.test(text)) {
diff --git a/conf/eslint-recommended.js b/conf/eslint-recommended.js
index 28d7aa4f9..847cd44c1 100644
--- a/conf/eslint-recommended.js
+++ b/conf/eslint-recommended.js
@@ -83,6 +83,7 @@ module.exports = {
         "newline-per-chained-call": "off",
         "no-alert": "off",
         "no-array-constructor": "off",
+        "no-async-promise-executor": "off",
         "no-await-in-loop": "off",
         "no-bitwise": "off",
         "no-buffer-constructor": "off",
@@ -139,6 +140,7 @@ module.exports = {
         "no-lonely-if": "off",
         "no-loop-func": "off",
         "no-magic-numbers": "off",
+        "no-misleading-character-class": "off",
         "no-mixed-operators": "off",
         "no-mixed-requires": "off",
         "no-mixed-spaces-and-tabs": "error",
@@ -240,8 +242,10 @@ module.exports = {
         "quote-props": "off",
         quotes: "off",
         radix: "off",
+        "require-atomic-updates": "off",
         "require-await": "off",
         "require-jsdoc": "off",
+        "require-unicode-regexp": "off",
         "require-yield": "error",
         "rest-spread-spacing": "off",
         semi: "off",
diff --git a/docs/rules/array-bracket-newline.md b/docs/rules/array-bracket-newline.md
index 72e0041d8..fd5236076 100644
--- a/docs/rules/array-bracket-newline.md
+++ b/docs/rules/array-bracket-newline.md
@@ -274,7 +274,7 @@ If you don't want to enforce line breaks after opening and before closing array
 
 ## Compatibility
 
-* **JSCS:** [validateNewlineAfterArrayElements](http://jscs.info/rule/validateNewlineAfterArrayElements)
+* **JSCS:** `validateNewlineAfterArrayElements`
 
 ## Related Rules
 
diff --git a/docs/rules/array-element-newline.md b/docs/rules/array-element-newline.md
index 6a3a66e1d..0d8ec82cd 100644
--- a/docs/rules/array-element-newline.md
+++ b/docs/rules/array-element-newline.md
@@ -290,7 +290,7 @@ If you don't want to enforce linebreaks between array elements, don't enable thi
 
 ## Compatibility
 
-* **JSCS:** [validateNewlineAfterArrayElements](http://jscs.info/rule/validateNewlineAfterArrayElements)
+* **JSCS:** `validateNewlineAfterArrayElements`
 
 ## Related Rules
 
diff --git a/docs/rules/capitalized-comments.md b/docs/rules/capitalized-comments.md
index 70078fc97..9861db7e8 100644
--- a/docs/rules/capitalized-comments.md
+++ b/docs/rules/capitalized-comments.md
@@ -245,4 +245,5 @@ This rule can be disabled if you do not care about the grammatical style of comm
 
 ## Compatibility
 
-* **JSCS**: [requireCapitalizedComments](http://jscs.info/rule/requireCapitalizedComments) and [disallowCapitalizedComments](http://jscs.info/rule/disallowCapitalizedComments)
+* **JSCS**: `requireCapitalizedComments`
+* **JSCS**: `disallowCapitalizedComments`
diff --git a/docs/rules/func-call-spacing.md b/docs/rules/func-call-spacing.md
index b97c95d70..0469998c0 100644
--- a/docs/rules/func-call-spacing.md
+++ b/docs/rules/func-call-spacing.md
@@ -101,5 +101,5 @@ This rule can safely be turned off if your project does not care about enforcing
 
 ## Compatibility
 
-- **JSCS**: [disallowSpacesInCallExpression](http://jscs.info/rule/disallowSpacesInCallExpression)
-- **JSCS**: [requireSpacesInCallExpression](http://jscs.info/rule/requireSpacesInCallExpression)
+- **JSCS**: `disallowSpacesInCallExpression`
+- **JSCS**: `requireSpacesInCallExpression`
diff --git a/docs/rules/func-name-matching.md b/docs/rules/func-name-matching.md
index 4d502869c..58c4c4ba9 100644
--- a/docs/rules/func-name-matching.md
+++ b/docs/rules/func-name-matching.md
@@ -137,4 +137,4 @@ Do not use this rule if you want to allow named functions to have different name
 
 ## Compatibility
 
-* **JSCS**: [requireMatchingFunctionName](http://jscs.info/rule/requireMatchingFunctionName)
+* **JSCS**: `requireMatchingFunctionName`
diff --git a/docs/rules/func-names.md b/docs/rules/func-names.md
index 758abc13f..0e17faea2 100644
--- a/docs/rules/func-names.md
+++ b/docs/rules/func-names.md
@@ -107,5 +107,5 @@ Foo.prototype.bar = function() {};
 
 ## Compatibility
 
-* **JSCS**: [requireAnonymousFunctions](http://jscs.info/rule/requireAnonymousFunctions)
-* **JSCS**: [disallowAnonymousFunctions](http://jscs.info/rule/disallowAnonymousFunctions)
+* **JSCS**: `requireAnonymousFunctions`
+* **JSCS**: `disallowAnonymousFunctions`
diff --git a/docs/rules/indent-legacy.md b/docs/rules/indent-legacy.md
index 28208de5d..e866fbf80 100644
--- a/docs/rules/indent-legacy.md
+++ b/docs/rules/indent-legacy.md
@@ -530,4 +530,4 @@ var foo = { bar: 1,
 ## Compatibility
 
 * **JSHint**: `indent`
-* **JSCS**: [validateIndentation](http://jscs.info/rule/validateIndentation)
+* **JSCS**: `validateIndentation`
diff --git a/docs/rules/indent.md b/docs/rules/indent.md
index 37dcabbd3..24e16a972 100644
--- a/docs/rules/indent.md
+++ b/docs/rules/indent.md
@@ -661,4 +661,4 @@ if (foo) {
 ## Compatibility
 
 * **JSHint**: `indent`
-* **JSCS**: [validateIndentation](http://jscs.info/rule/validateIndentation)
+* **JSCS**: `validateIndentation`
diff --git a/docs/rules/line-comment-position.md b/docs/rules/line-comment-position.md
index 63561c831..993abc02c 100644
--- a/docs/rules/line-comment-position.md
+++ b/docs/rules/line-comment-position.md
@@ -103,4 +103,4 @@ If you aren't concerned about having different line comment styles, then you can
 
 ## Compatibility
 
-**JSCS**: [validateCommentPosition](http://jscs.info/rule/validateCommentPosition)
+**JSCS**: `validateCommentPosition`
diff --git a/docs/rules/linebreak-style.md b/docs/rules/linebreak-style.md
index 96f6c9f50..f8c2a05bd 100644
--- a/docs/rules/linebreak-style.md
+++ b/docs/rules/linebreak-style.md
@@ -83,4 +83,4 @@ If you aren't concerned about having different line endings within your code, th
 
 ## Compatibility
 
-* **JSCS**: [validateLineBreaks](http://jscs.info/rule/validateLineBreaks)
+* **JSCS**: `validateLineBreaks`
diff --git a/docs/rules/lines-around-directive.md b/docs/rules/lines-around-directive.md
index 3f9890bc4..eebf6d3c9 100644
--- a/docs/rules/lines-around-directive.md
+++ b/docs/rules/lines-around-directive.md
@@ -318,5 +318,5 @@ You can safely disable this rule if you do not have any strict conventions about
 
 ## Compatibility
 
-* **JSCS**: [requirePaddingNewLinesAfterUseStrict](http://jscs.info/rule/requirePaddingNewLinesAfterUseStrict)
-* **JSCS**: [disallowPaddingNewLinesAfterUseStrict](http://jscs.info/rule/disallowPaddingNewLinesAfterUseStrict)
+* **JSCS**: `requirePaddingNewLinesAfterUseStrict`
+* **JSCS**: `disallowPaddingNewLinesAfterUseStrict`
diff --git a/docs/rules/lines-between-class-members.md b/docs/rules/lines-between-class-members.md
index e0429fdf8..a287f997e 100644
--- a/docs/rules/lines-between-class-members.md
+++ b/docs/rules/lines-between-class-members.md
@@ -103,5 +103,8 @@ If you don't want to enforce empty lines between class members, you can disable
 
 * [padded-blocks](padded-blocks.md)
 * [padding-line-between-statements](padding-line-between-statements.md)
-* [requirePaddingNewLinesAfterBlocks](http://jscs.info/rule/requirePaddingNewLinesAfterBlocks)
-* [disallowPaddingNewLinesAfterBlocks](http://jscs.info/rule/disallowPaddingNewLinesAfterBlocks)
+
+## Compatibility
+
+* **JSCS**: `requirePaddingNewLinesAfterBlocks`
+* **JSCS**: `disallowPaddingNewLinesAfterBlocks`
diff --git a/docs/rules/max-lines.md b/docs/rules/max-lines.md
index 097804570..648852630 100644
--- a/docs/rules/max-lines.md
+++ b/docs/rules/max-lines.md
@@ -123,4 +123,4 @@ You can turn this rule off if you are not concerned with the number of lines in
 
 ## Compatibility
 
-* **JSCS**: [maximumNumberOfLines](http://jscs.info/rule/maximumNumberOfLines)
+* **JSCS**: `maximumNumberOfLines`
diff --git a/docs/rules/multiline-ternary.md b/docs/rules/multiline-ternary.md
index 0cb94643a..a1a8446bc 100644
--- a/docs/rules/multiline-ternary.md
+++ b/docs/rules/multiline-ternary.md
@@ -146,4 +146,4 @@ You can safely disable this rule if you do not have any strict conventions about
 
 ## Compatibility
 
-* **JSCS**: [requireMultiLineTernary](http://jscs.info/rule/requireMultiLineTernary)
+* **JSCS**: `requireMultiLineTernary`
diff --git a/docs/rules/no-async-promise-executor.md b/docs/rules/no-async-promise-executor.md
new file mode 100644
index 000000000..82fed5369
--- /dev/null
+++ b/docs/rules/no-async-promise-executor.md
@@ -0,0 +1,62 @@
+# disallow using an async function as a Promise executor (no-async-promise-executor)
+
+The `new Promise` constructor accepts an *executor* function as an argument, which has `resolve` and `reject` parameters that can be used to control the state of the created Promise. For example:
+
+```js
+const result = new Promise(function executor(resolve, reject) {
+  readFile('foo.txt', function(err, result) {
+    if (err) {
+      reject(err);
+    } else {
+      resolve(result);
+    }
+  });
+});
+```
+
+The executor function can also be an `async function`. However, this is usually a mistake, for a few reasons:
+
+* If an async executor function throws an error, the error will be lost and won't cause the newly-constructed `Promise` to reject. This could make it difficult to debug and handle some errors.
+* If a Promise executor function is using `await`, this is usually a sign that it is not actually necessary to use the `new Promise` constructor, or the scope of the `new Promise` constructor can be reduced.
+
+## Rule Details
+
+This rule aims to disallow async Promise executor functions.
+
+Examples of **incorrect** code for this rule:
+
+```js
+const result = new Promise(async (resolve, reject) => {
+  readFile('foo.txt', function(err, result) {
+    if (err) {
+      reject(err);
+    } else {
+      resolve(result);
+    }
+  });
+});
+
+const result = new Promise(async (resolve, reject) => {
+  resolve(await foo);
+});
+```
+
+Examples of **correct** code for this rule:
+
+```js
+const result = new Promise((resolve, reject) => {
+  readFile('foo.txt', function(err, result) {
+    if (err) {
+      reject(err);
+    } else {
+      resolve(result);
+    }
+  });
+});
+
+const result = Promise.resolve(foo);
+```
+
+## When Not To Use It
+
+If your codebase doesn't support async function syntax, there's no need to enable this rule.
diff --git a/docs/rules/no-await-in-loop.md b/docs/rules/no-await-in-loop.md
index d726b25e4..9edf07363 100644
--- a/docs/rules/no-await-in-loop.md
+++ b/docs/rules/no-await-in-loop.md
@@ -70,5 +70,6 @@ async function foo(things) {
 
 In many cases the iterations of a loop are not actually independent of each-other. For example, the
 output of one iteration might be used as the input to another. Or, loops may be used to retry
-asynchronous operations that were unsuccessful. In such cases it makes sense to use `await` within a
+asynchronous operations that were unsuccessful. Or, loops may be used to prevent your code from sending
+an excessive amount of requests in parallel. In such cases it makes sense to use `await` within a
 loop and it is recommended to disable the rule via a standard ESLint disable comment.
diff --git a/docs/rules/no-else-return.md b/docs/rules/no-else-return.md
index eb6f8fab3..2f3f83d73 100644
--- a/docs/rules/no-else-return.md
+++ b/docs/rules/no-else-return.md
@@ -20,14 +20,6 @@ This rule is aimed at highlighting an unnecessary block of code following an `if
 
 This rule has an object option:
 
-```json
-{
-    "no-else-return": ["error", { "allowElseIf": true }],
-    // or
-    "no-else-return": ["error", { "allowElseIf": false }]
-}
-```
-
 * `allowElseIf: true` (default) allows `else if` blocks after a return
 * `allowElseIf: false` disallows `else if` blocks after a return
 
diff --git a/docs/rules/no-misleading-character-class.md b/docs/rules/no-misleading-character-class.md
new file mode 100644
index 000000000..f6ef2fb9a
--- /dev/null
+++ b/docs/rules/no-misleading-character-class.md
@@ -0,0 +1,73 @@
+# Disallow characters which are made with multiple code points in character class syntax (no-misleading-character-class)
+
+Unicode includes the characters which are made with multiple code points.
+RegExp character class syntax (`/[abc]/`) cannot handle characters which are made by multiple code points as a character; those characters will be dissolved to each code point. For example, `❇️` is made by `❇` (`U+2747`) and VARIATION SELECTOR-16 (`U+FE0F`). If this character is in RegExp character class, it will match to either `❇` (`U+2747`) or VARIATION SELECTOR-16 (`U+FE0F`) rather than `❇️`.
+
+This rule reports the regular expressions which include multiple code point characters in character class syntax. This rule considers the following characters as multiple code point characters.
+
+**A character with combining characters:**
+
+The combining characters are characters which belong to one of `Mc`, `Me`, and `Mn` [Unicode general categories](http://www.unicode.org/L2/L1999/UnicodeData.html#General%20Category).
+
+```js
+/^[Á]$/u.test("Á") //→ false
+/^[❇️]$/u.test("❇️") //→ false
+```
+
+**A character with Emoji modifiers:**
+
+```js
+/^[👶🏻]$/u.test("👶🏻") //→ false
+/^[👶🏽]$/u.test("👶🏽") //→ false
+```
+
+**A pair of regional indicator symbols:**
+
+```js
+/^[🇯🇵]$/u.test("🇯🇵") //→ false
+```
+
+**Characters that ZWJ joins:**
+
+```js
+/^[👨‍👩‍👦]$/u.test("👨‍👩‍👦") //→ false
+```
+
+**A surrogate pair without Unicode flag:**
+
+```js
+/^[👍]$/.test("👍") //→ false
+
+// Surrogate pair is OK if with u flag.
+/^[👍]$/u.test("👍") //→ true
+```
+
+## Rule Details
+
+This rule reports the regular expressions which include multiple code point characters in character class syntax.
+
+Examples of **incorrect** code for this rule:
+
+```js
+/*eslint no-misleading-character-class: error */
+
+/^[Á]$/u
+/^[❇️]$/u
+/^[👶🏻]$/u
+/^[🇯🇵]$/u
+/^[👨‍👩‍👦]$/u
+/^[👍]$/
+```
+
+Examples of **correct** code for this rule:
+
+```js
+/*eslint no-misleading-character-class: error */
+
+/^[abc]$/
+/^[👍]$/u
+```
+
+## When Not To Use It
+
+You can turn this rule off if you don't want to check RegExp character class syntax for multiple code point characters.
diff --git a/docs/rules/no-return-await.md b/docs/rules/no-return-await.md
index 6c82d0bc1..c30fc60a6 100644
--- a/docs/rules/no-return-await.md
+++ b/docs/rules/no-return-await.md
@@ -1,6 +1,6 @@
 # Disallows unnecessary `return await` (no-return-await)
 
-Inside an `async function`, `return await` is useless. Since the return value of an `async function` is always wrapped in `Promise.resolve`, `return await` doesn't actually do anything except add extra time before the overarching Promise resolves or rejects. This pattern is almost certainly due to programmer ignorance of the return semantics of `async function`s.
+Inside an `async function`, `return await` is seldom useful. Since the return value of an `async function` is always wrapped in `Promise.resolve`, `return await` doesn’t actually do anything except add extra time before the overarching Promise resolves or rejects. The only valid exception is if `return await` is used in a try/catch statement to catch errors from another Promise-based function.
 
 ## Rule Details
 
@@ -10,7 +10,7 @@ The following patterns are considered warnings:
 
 ```js
 async function foo() {
-  return await bar();
+    return await bar();
 }
 ```
 
@@ -18,23 +18,23 @@ The following patterns are not warnings:
 
 ```js
 async function foo() {
-  return bar();
+    return bar();
 }
 
 async function foo() {
-  await bar();
-  return;
+    await bar();
+    return;
 }
 
 async function foo() {
-  const x = await bar();
-  return x;
+    const x = await bar();
+    return x;
 }
 
 async function foo() {
-  try {
-    return await bar();
-  } catch (error) {}
+    try {
+        return await bar();
+    } catch (error) {}
 }
 ```
 
diff --git a/docs/rules/no-tabs.md b/docs/rules/no-tabs.md
index 57921aa31..2ad52bb3e 100644
--- a/docs/rules/no-tabs.md
+++ b/docs/rules/no-tabs.md
@@ -38,4 +38,4 @@ If you have established a standard where having tabs is fine.
 
 ## Compatibility
 
-* **JSCS**: [disallowTabs](http://jscs.info/rule/disallowTabs)
+* **JSCS**: `disallowTabs`
diff --git a/docs/rules/no-useless-rename.md b/docs/rules/no-useless-rename.md
index f765fb390..d4f781582 100644
--- a/docs/rules/no-useless-rename.md
+++ b/docs/rules/no-useless-rename.md
@@ -117,4 +117,4 @@ You can safely disable this rule if you do not care about redundantly renaming i
 
 ## Compatibility
 
-* **JSCS**: [disallowIdenticalDestructuringNames](http://jscs.info/rule/disallowIdenticalDestructuringNames)
+* **JSCS**: `disallowIdenticalDestructuringNames`
diff --git a/docs/rules/nonblock-statement-body-position.md b/docs/rules/nonblock-statement-body-position.md
index 0a05d2945..3e05cce86 100644
--- a/docs/rules/nonblock-statement-body-position.md
+++ b/docs/rules/nonblock-statement-body-position.md
@@ -155,4 +155,4 @@ If you're not concerned about consistent locations of single-line statements, yo
 
 ## Further Reading
 
-* JSCS: [requireNewlineBeforeSingleStatementsInIf](http://jscs.info/rule/requireNewlineBeforeSingleStatementsInIf)
+* JSCS: `requireNewlineBeforeSingleStatementsInIf`
diff --git a/docs/rules/object-curly-newline.md b/docs/rules/object-curly-newline.md
index d62fdf996..6b99f72e7 100644
--- a/docs/rules/object-curly-newline.md
+++ b/docs/rules/object-curly-newline.md
@@ -511,7 +511,8 @@ export { foo as f, bar } from 'foo-bar';
 
 ## Compatibility
 
-* **JSCS**: [requirePaddingNewLinesInObjects](http://jscs.info/rule/requirePaddingNewLinesInObjects) and [disallowPaddingNewLinesInObjects](http://jscs.info/rule/disallowPaddingNewLinesInObjects)
+* **JSCS**: `requirePaddingNewLinesInObjects`
+* **JSCS**: `disallowPaddingNewLinesInObjects`
 
 ## When Not To Use It
 
diff --git a/docs/rules/object-property-newline.md b/docs/rules/object-property-newline.md
index 15d8ee0a0..963d6ee26 100644
--- a/docs/rules/object-property-newline.md
+++ b/docs/rules/object-property-newline.md
@@ -260,7 +260,7 @@ You can turn this rule off if you want to decide, case-by-case, whether to place
 
 ## Compatibility
 
-- **JSCS**: This rule provides partial compatibility with [requireObjectKeysOnNewLine](http://jscs.info/rule/requireObjectKeysOnNewLine).
+- **JSCS**: This rule provides partial compatibility with `requireObjectKeysOnNewLine`.
 
 ## Related Rules
 
diff --git a/docs/rules/one-var.md b/docs/rules/one-var.md
index 53851ab5b..447346d71 100644
--- a/docs/rules/one-var.md
+++ b/docs/rules/one-var.md
@@ -536,5 +536,5 @@ function foo() {
 ## Compatibility
 
 * **JSHint**: This rule maps to the `onevar` JSHint rule, but allows `let` and `const` to be configured separately.
-* **JSCS**: This rule roughly maps to [disallowMultipleVarDecl](http://jscs.info/rule/disallowMultipleVarDecl).
-* **JSCS**: This rule option `separateRequires` roughly maps to [requireMultipleVarDecl](http://jscs.info/rule/requireMultipleVarDecl).
+* **JSCS**: This rule roughly maps to `disallowMultipleVarDecl`.
+* **JSCS**: This rule option `separateRequires` roughly maps to `requireMultipleVarDecl`.
diff --git a/docs/rules/prefer-numeric-literals.md b/docs/rules/prefer-numeric-literals.md
index 965fd529b..13bc7a716 100644
--- a/docs/rules/prefer-numeric-literals.md
+++ b/docs/rules/prefer-numeric-literals.md
@@ -53,4 +53,4 @@ If you want to allow use of `parseInt()` or `Number.parseInt()` for binary, octa
 
 ## Compatibility
 
-* **JSCS**: [requireNumericLiterals](http://jscs.info/rule/requireNumericLiterals)
+* **JSCS**: `requireNumericLiterals`
diff --git a/docs/rules/prefer-object-spread.md b/docs/rules/prefer-object-spread.md
index 0907170e4..b50e39716 100644
--- a/docs/rules/prefer-object-spread.md
+++ b/docs/rules/prefer-object-spread.md
@@ -2,6 +2,8 @@
 
 When Object.assign is called using an object literal as the first argument, this rule requires using the object spread syntax instead. This rule also warns on cases where an `Object.assign` call is made using a single argument that is an object literal, in this case, the `Object.assign` call is not needed.
 
+Object spread is a declarative alternative which may perform better than the more dynamic, imperative `Object.assign`.
+
 ## Rule Details
 
 Examples of **incorrect** code for this rule:
@@ -44,4 +46,4 @@ Object.assign(foo, { ...baz });
 
 ## When Not To Use It
 
-When you don't care about syntactic sugar added by the object spread property.
+When object spread is not available in your codebase.
diff --git a/docs/rules/require-atomic-updates.md b/docs/rules/require-atomic-updates.md
new file mode 100644
index 000000000..593ccdd60
--- /dev/null
+++ b/docs/rules/require-atomic-updates.md
@@ -0,0 +1,97 @@
+# Disallow assignments that can lead to race conditions due to usage of `await` or `yield` (require-atomic-updates)
+
+When writing asynchronous code, it is possible to create subtle race condition bugs. Consider the following example:
+
+```js
+let totalLength = 0;
+
+async function addLengthOfSinglePage(pageNum) {
+  totalLength += await getPageLength(pageNum);
+}
+
+Promise.all([addLengthOfSinglePage(1), addLengthOfSinglePage(2)]).then(() => {
+  console.log('The combined length of both pages is', totalLength);
+});
+```
+
+This code looks like it will sum the results of calling `getPageLength(1)` and `getPageLength(2)`, but in reality the final value of `totalLength` will only be the length of one of the two pages. The bug is in the statement `totalLength += await getPageLength(pageNum);`. This statement first reads an initial value of `totalLength`, then calls `getPageLength(pageNum)` and waits for that Promise to fulfill. Finally, it sets the value of `totalLength` to the sum of `await getPageLength(pageNum)` and the *initial* value of `totalLength`. If the `totalLength` variable is updated in a separate function call during the time that the `getPageLength(pageNum)` Promise is pending, that update will be lost because the new value is overwritten without being read.
+
+One way to fix this issue would be to ensure that `totalLength` is read at the same time as it's updated, like this:
+
+```js
+async function addLengthOfSinglePage(pageNum) {
+  const lengthOfThisPage = await getPageLength(pageNum);
+
+  totalLength += lengthOfThisPage;
+}
+```
+
+Another solution would be to avoid using a mutable variable reference at all:
+
+```js
+Promise.all([getPageLength(1), getPageLength(2)]).then(pageLengths => {
+  const totalLength = pageLengths.reduce((accumulator, length) => accumulator + length, 0);
+
+  console.log('The combined length of both pages is', totalLength);
+});
+```
+
+## Rule Details
+
+This rule aims to report assignments to variables or properties where all of the following are true:
+
+* A variable or property is reassigned to a new value which is based on its old value.
+* A `yield` or `await` expression interrupts the assignment after the old value is read, and before the new value is set.
+* The rule cannot easily verify that the assignment is safe (e.g. if an assigned variable is local and would not be readable from anywhere else while the function is paused).
+
+Examples of **incorrect** code for this rule:
+
+```js
+/* eslint require-atomic-updates: error */
+
+let result;
+async function foo() {
+  result += await somethingElse;
+
+  result = result + await somethingElse;
+
+  result = result + doSomething(await somethingElse);
+}
+
+function* bar() {
+  result += yield;
+
+  result = result + (yield somethingElse);
+
+  result = result + doSomething(yield somethingElse);
+}
+```
+
+Examples of **correct** code for this rule:
+
+```js
+/* eslint require-atomic-updates: error */
+
+let result;
+async function foo() {
+  result = await somethingElse + result;
+
+  let tmp = await somethingElse;
+  result += tmp;
+
+  let localVariable = 0;
+  localVariable += await somethingElse;
+}
+
+function* bar() {
+  result += yield;
+
+  result = (yield somethingElse) + result;
+
+  result = doSomething(yield somethingElse, result);
+}
+```
+
+## When Not To Use It
+
+If you don't use async or generator functions, you don't need to enable this rule.
diff --git a/docs/rules/require-unicode-regexp.md b/docs/rules/require-unicode-regexp.md
new file mode 100644
index 000000000..3077d4dac
--- /dev/null
+++ b/docs/rules/require-unicode-regexp.md
@@ -0,0 +1,55 @@
+# Enforce the use of `u` flag on RegExp (require-unicode-regexp)
+
+RegExp `u` flag has two effects:
+
+1. **Make the regular expression handling UTF-16 surrogate pairs correctly.**
+
+    Especially, character range syntax gets the correct behavior.
+
+    ```js
+    /^[👍]$/.test("👍") //→ false
+    /^[👍]$/u.test("👍") //→ true
+    ```
+
+2. **Make the regular expression throwing syntax errors early as disabling [Annex B extensions](https://www.ecma-international.org/ecma-262/6.0/#sec-regular-expressions-patterns).**
+
+    Because of historical reason, JavaScript regular expressions are tolerant of syntax errors. For example, `/\w{1, 2/` is a syntax error, but JavaScript doesn't throw the error. It matches strings such as `"a{1, 2"` instead. Such a recovering logic is defined in Annex B.
+
+    The `u` flag disables the recovering logic Annex B defined. As a result, you can find errors early. This is similar to [the strict mode](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode).
+
+Therefore, the `u` flag lets us work better with regular expressions.
+
+## Rule Details
+
+This rule aims to enforce the use of `u` flag on regular expressions.
+
+Examples of **incorrect** code for this rule:
+
+```js
+/*eslint require-unicode-regexp: error */
+
+const a = /aaa/
+const b = /bbb/gi
+const c = new RegExp("ccc")
+const d = new RegExp("ddd", "gi")
+```
+
+Examples of **correct** code for this rule:
+
+```js
+/*eslint require-unicode-regexp: error */
+
+const a = /aaa/u
+const b = /bbb/giu
+const c = new RegExp("ccc", "u")
+const d = new RegExp("ddd", "giu")
+
+// This rule ignores RegExp calls if the flags could not be evaluated to a static value.
+function f(flags) {
+    return new RegExp("eee", flags)
+}
+```
+
+## When Not To Use It
+
+If you don't want to notify regular expressions with no `u` flag, then it's safe to disable this rule.
diff --git a/docs/rules/sort-keys.md b/docs/rules/sort-keys.md
index d3f135a9e..5370210b7 100644
--- a/docs/rules/sort-keys.md
+++ b/docs/rules/sort-keys.md
@@ -178,4 +178,4 @@ If you don't want to notify about properties' order, then it's safe to disable t
 
 ## Compatibility
 
-* **JSCS:** [validateOrderInObjectKeys](http://jscs.info/rule/validateOrderInObjectKeys)
+* **JSCS:** `validateOrderInObjectKeys`
diff --git a/docs/user-guide/configuring.md b/docs/user-guide/configuring.md
index b1284f92a..4daa7dd59 100644
--- a/docs/user-guide/configuring.md
+++ b/docs/user-guide/configuring.md
@@ -272,6 +272,8 @@ ESLint comes with a large number of rules. You can modify which rules your proje
 * `"warn"` or `1` - turn the rule on as a warning (doesn't affect exit code)
 * `"error"` or `2` - turn the rule on as an error (exit code is 1 when triggered)
 
+### Using Configuration Comments
+
 To configure rules inside of a file using configuration comments, use a comment in the following format:
 
 ```js
@@ -294,6 +296,8 @@ If a rule has additional options, you can specify them using array literal synta
 
 This comment specifies the "double" option for the [`quotes`](../rules/quotes) rule. The first item in the array is always the rule severity (number or string).
 
+### Using Configuration Files
+
 To configure rules inside of a configuration file, use the `rules` key along with an error level and any options you want to use. For example:
 
 
diff --git a/lib/cli-engine.js b/lib/cli-engine.js
index aa0f5521c..9d7246d1e 100644
--- a/lib/cli-engine.js
+++ b/lib/cli-engine.js
@@ -22,7 +22,7 @@ const fs = require("fs"),
     IgnoredPaths = require("./ignored-paths"),
     Config = require("./config"),
     LintResultCache = require("./util/lint-result-cache"),
-    globUtil = require("./util/glob-util"),
+    globUtils = require("./util/glob-utils"),
     validator = require("./config/config-validator"),
     hash = require("./util/hash"),
     ModuleResolver = require("./util/module-resolver"),
@@ -492,7 +492,7 @@ class CLIEngine {
      * @returns {string[]} The equivalent glob patterns.
      */
     resolveFileGlobPatterns(patterns) {
-        return globUtil.resolveFileGlobPatterns(patterns.filter(Boolean), this.options);
+        return globUtils.resolveFileGlobPatterns(patterns.filter(Boolean), this.options);
     }
 
     /**
@@ -511,25 +511,25 @@ class CLIEngine {
         }
 
         const startTime = Date.now();
-        const fileList = globUtil.listFilesToProcess(patterns, options);
+        const fileList = globUtils.listFilesToProcess(patterns, options);
         const results = fileList.map(fileInfo => {
             if (fileInfo.ignored) {
                 return createIgnoreResult(fileInfo.filename, options.cwd);
             }
 
             if (options.cache) {
-
-                /*
-                 * get the descriptor for this file
-                 * with the metadata and the flag that determines if
-                 * the file has changed
-                 */
                 const cachedLintResults = lintResultCache.getCachedLintResults(fileInfo.filename);
 
                 if (cachedLintResults) {
-                    debug(`Skipping file since it hasn't changed: ${fileInfo.filename}`);
+                    const resultHadMessages = cachedLintResults.messages && cachedLintResults.messages.length;
+
+                    if (resultHadMessages && options.fix) {
+                        debug(`Reprocessing cached file to allow autofix: ${fileInfo.filename}`);
+                    } else {
+                        debug(`Skipping file since it hasn't changed: ${fileInfo.filename}`);
 
-                    return cachedLintResults;
+                        return cachedLintResults;
+                    }
                 }
             }
 
diff --git a/lib/code-path-analysis/code-path-analyzer.js b/lib/code-path-analysis/code-path-analyzer.js
index f4a7fee7f..b81e212e7 100644
--- a/lib/code-path-analysis/code-path-analyzer.js
+++ b/lib/code-path-analysis/code-path-analyzer.js
@@ -14,7 +14,7 @@ const assert = require("assert"),
     CodePathSegment = require("./code-path-segment"),
     IdGenerator = require("./id-generator"),
     debug = require("./debug-helpers"),
-    astUtils = require("../ast-utils");
+    astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Helpers
diff --git a/lib/config.js b/lib/config.js
index 2eeaad181..8ea9aeb6f 100644
--- a/lib/config.js
+++ b/lib/config.js
@@ -15,7 +15,7 @@ const path = require("path"),
     ConfigFile = require("./config/config-file"),
     ConfigCache = require("./config/config-cache"),
     Plugins = require("./config/plugins"),
-    FileFinder = require("./file-finder"),
+    FileFinder = require("./util/file-finder"),
     isResolvable = require("is-resolvable");
 
 const debug = require("debug")("eslint:config");
diff --git a/lib/config/config-initializer.js b/lib/config/config-initializer.js
index 4273abae5..a6791ba85 100644
--- a/lib/config/config-initializer.js
+++ b/lib/config/config-initializer.js
@@ -16,9 +16,9 @@ const util = require("util"),
     autoconfig = require("./autoconfig.js"),
     ConfigFile = require("./config-file"),
     ConfigOps = require("./config-ops"),
-    getSourceCodeOfFiles = require("../util/source-code-util").getSourceCodeOfFiles,
+    getSourceCodeOfFiles = require("../util/source-code-utils").getSourceCodeOfFiles,
     ModuleResolver = require("../util/module-resolver"),
-    npmUtil = require("../util/npm-util"),
+    npmUtils = require("../util/npm-utils"),
     recConfig = require("../../conf/eslint-recommended"),
     log = require("../util/logging");
 
@@ -61,7 +61,7 @@ function writeFile(config, format) {
 /**
  * Get the peer dependencies of the given module.
  * This adds the gotten value to cache at the first time, then reuses it.
- * In a process, this function is called twice, but `npmUtil.fetchPeerDependencies` needs to access network which is relatively slow.
+ * In a process, this function is called twice, but `npmUtils.fetchPeerDependencies` needs to access network which is relatively slow.
  * @param {string} moduleName The module name to get.
  * @returns {Object} The peer dependencies of the given module.
  * This object is the object of `peerDependencies` field of `package.json`.
@@ -73,7 +73,7 @@ function getPeerDependencies(moduleName) {
     if (!result) {
         log.info(`Checking peerDependencies of ${moduleName}`);
 
-        result = npmUtil.fetchPeerDependencies(moduleName);
+        result = npmUtils.fetchPeerDependencies(moduleName);
         getPeerDependencies.cache.set(moduleName, result);
     }
 
@@ -109,7 +109,7 @@ function getModulesList(config, installESLint) {
     if (installESLint === false) {
         delete modules.eslint;
     } else {
-        const installStatus = npmUtil.checkDevDeps(["eslint"]);
+        const installStatus = npmUtils.checkDevDeps(["eslint"]);
 
         // Mark to show messages if it's new installation of eslint.
         if (installStatus.eslint === false) {
@@ -373,7 +373,7 @@ function hasESLintVersionConflict(answers) {
  */
 function installModules(modules) {
     log.info(`Installing ${modules.join(", ")}`);
-    npmUtil.installSyncSaveDev(modules);
+    npmUtils.installSyncSaveDev(modules);
 }
 
 /* istanbul ignore next: no need to test inquirer */
@@ -438,7 +438,7 @@ function promptUser() {
                 { name: "Google (https://github.com/google/eslint-config-google)", value: "google" }
             ],
             when(answers) {
-                answers.packageJsonExists = npmUtil.checkPackageJson();
+                answers.packageJsonExists = npmUtils.checkPackageJson();
                 return answers.source === "guide" && answers.packageJsonExists;
             }
         },
diff --git a/lib/ignored-paths.js b/lib/ignored-paths.js
index 8134d6d32..8520090af 100644
--- a/lib/ignored-paths.js
+++ b/lib/ignored-paths.js
@@ -12,7 +12,7 @@
 const fs = require("fs"),
     path = require("path"),
     ignore = require("ignore"),
-    pathUtil = require("./util/path-util");
+    pathUtils = require("./util/path-utils");
 
 const debug = require("debug")("eslint:ignored-paths");
 
@@ -79,6 +79,40 @@ function mergeDefaultOptions(options) {
     return Object.assign({}, DEFAULT_OPTIONS, options);
 }
 
+/* eslint-disable valid-jsdoc */
+/**
+ * Normalize the path separators in a given string.
+ * On Windows environment, this replaces `\` by `/`.
+ * Otherwrise, this does nothing.
+ * @param {string} str The path string to normalize.
+ * @returns {string} The normalized path.
+ */
+const normalizePathSeps = path.sep === "/"
+    ? (str => str)
+    : ((seps, str) => str.replace(seps, "/")).bind(null, new RegExp(`\\${path.sep}`, "g"));
+/* eslint-enable valid-jsdoc */
+
+/**
+ * Converts a glob pattern to a new glob pattern relative to a different directory
+ * @param {string} globPattern The glob pattern, relative the the old base directory
+ * @param {string} relativePathToOldBaseDir A relative path from the new base directory to the old one
+ * @returns {string} A glob pattern relative to the new base directory
+ */
+function relativize(globPattern, relativePathToOldBaseDir) {
+    if (relativePathToOldBaseDir === "") {
+        return globPattern;
+    }
+
+    const prefix = globPattern.startsWith("!") ? "!" : "";
+    const globWithoutPrefix = globPattern.replace(/^!/, "");
+
+    if (globWithoutPrefix.startsWith("/")) {
+        return `${prefix}/${normalizePathSeps(relativePathToOldBaseDir)}${globWithoutPrefix}`;
+    }
+
+    return globPattern;
+}
+
 //------------------------------------------------------------------------------
 // Public Interface
 //------------------------------------------------------------------------------
@@ -96,41 +130,36 @@ class IgnoredPaths {
 
         this.cache = {};
 
-        /**
-         * add pattern to node-ignore instance
-         * @param {Object} ig, instance of node-ignore
-         * @param {string} pattern, pattern do add to ig
-         * @returns {array} raw ignore rules
-         */
-        function addPattern(ig, pattern) {
-            return ig.addPattern(pattern);
-        }
-
         this.defaultPatterns = [].concat(DEFAULT_IGNORE_DIRS, options.patterns || []);
-        this.baseDir = options.cwd;
+
+        this.ignoreFileDir = options.ignore !== false && options.ignorePath
+            ? path.dirname(path.resolve(options.cwd, options.ignorePath))
+            : options.cwd;
+        this.options = options;
+        this._baseDir = null;
 
         this.ig = {
             custom: ignore(),
             default: ignore()
         };
 
-        /*
-         * Add a way to keep track of ignored files.  This was present in node-ignore
-         * 2.x, but dropped for now as of 3.0.10.
-         */
-        this.ig.custom.ignoreFiles = [];
-        this.ig.default.ignoreFiles = [];
-
+        this.defaultPatterns.forEach(pattern => this.addPatternRelativeToCwd(this.ig.default, pattern));
         if (options.dotfiles !== true) {
 
             /*
              * ignore files beginning with a dot, but not files in a parent or
              * ancestor directory (which in relative format will begin with `../`).
              */
-            addPattern(this.ig.default, [".*", "!../"]);
+            this.addPatternRelativeToCwd(this.ig.default, ".*");
+            this.addPatternRelativeToCwd(this.ig.default, "!../");
         }
 
-        addPattern(this.ig.default, this.defaultPatterns);
+        /*
+         * Add a way to keep track of ignored files.  This was present in node-ignore
+         * 2.x, but dropped for now as of 3.0.10.
+         */
+        this.ig.custom.ignoreFiles = [];
+        this.ig.default.ignoreFiles = [];
 
         if (options.ignore !== false) {
             let ignorePath;
@@ -154,13 +183,11 @@ class IgnoredPaths {
                     debug(`Loaded ignore file ${ignorePath}`);
                 } catch (e) {
                     debug("Could not find ignore file in cwd");
-                    this.options = options;
                 }
             }
 
             if (ignorePath) {
                 debug(`Adding ${ignorePath}`);
-                this.baseDir = path.dirname(path.resolve(options.cwd, ignorePath));
                 this.addIgnoreFile(this.ig.custom, ignorePath);
                 this.addIgnoreFile(this.ig.default, ignorePath);
             } else {
@@ -187,8 +214,8 @@ class IgnoredPaths {
                         if (packageJSONOptions.eslintIgnore) {
                             if (Array.isArray(packageJSONOptions.eslintIgnore)) {
                                 packageJSONOptions.eslintIgnore.forEach(pattern => {
-                                    addPattern(this.ig.custom, pattern);
-                                    addPattern(this.ig.default, pattern);
+                                    this.addPatternRelativeToIgnoreFile(this.ig.custom, pattern);
+                                    this.addPatternRelativeToIgnoreFile(this.ig.default, pattern);
                                 });
                             } else {
                                 throw new TypeError("Package.json eslintIgnore property requires an array of paths");
@@ -202,12 +229,68 @@ class IgnoredPaths {
             }
 
             if (options.ignorePattern) {
-                addPattern(this.ig.custom, options.ignorePattern);
-                addPattern(this.ig.default, options.ignorePattern);
+                this.addPatternRelativeToCwd(this.ig.custom, options.ignorePattern);
+                this.addPatternRelativeToCwd(this.ig.default, options.ignorePattern);
             }
         }
+    }
 
-        this.options = options;
+    /*
+     * If `ignoreFileDir` is a subdirectory of `cwd`, all paths will be normalized to be relative to `cwd`.
+     * Otherwise, all paths will be normalized to be relative to `ignoreFileDir`.
+     * This ensures that the final normalized ignore rule will not contain `..`, which is forbidden in
+     * ignore rules.
+     */
+
+    addPatternRelativeToCwd(ig, pattern) {
+        const baseDir = this.getBaseDir();
+        const cookedPattern = baseDir === this.options.cwd
+            ? pattern
+            : relativize(pattern, path.relative(baseDir, this.options.cwd));
+
+        ig.addPattern(cookedPattern);
+        debug("addPatternRelativeToCwd:\n  original = %j\n  cooked   = %j", pattern, cookedPattern);
+    }
+
+    addPatternRelativeToIgnoreFile(ig, pattern) {
+        const baseDir = this.getBaseDir();
+        const cookedPattern = baseDir === this.ignoreFileDir
+            ? pattern
+            : relativize(pattern, path.relative(baseDir, this.ignoreFileDir));
+
+        ig.addPattern(cookedPattern);
+        debug("addPatternRelativeToIgnoreFile:\n  original = %j\n  cooked   = %j", pattern, cookedPattern);
+    }
+
+    // Detect the common ancestor
+    getBaseDir() {
+        if (!this._baseDir) {
+            const a = path.resolve(this.options.cwd);
+            const b = path.resolve(this.ignoreFileDir);
+            let lastSepPos = 0;
+
+            // Set the shorter one (it's the common ancestor if one includes the other).
+            this._baseDir = a.length < b.length ? a : b;
+
+            // Set the common ancestor.
+            for (let i = 0; i < a.length && i < b.length; ++i) {
+                if (a[i] !== b[i]) {
+                    this._baseDir = a.slice(0, lastSepPos);
+                    break;
+                }
+                if (a[i] === path.sep) {
+                    lastSepPos = i;
+                }
+            }
+
+            // If it's only Windows drive letter, it needs \
+            if (/^[A-Z]:$/.test(this._baseDir)) {
+                this._baseDir += "\\";
+            }
+
+            debug("baseDir = %j", this._baseDir);
+        }
+        return this._baseDir;
     }
 
     /**
@@ -217,7 +300,7 @@ class IgnoredPaths {
      */
     readIgnoreFile(filePath) {
         if (typeof this.cache[filePath] === "undefined") {
-            this.cache[filePath] = fs.readFileSync(filePath, "utf8");
+            this.cache[filePath] = fs.readFileSync(filePath, "utf8").split(/\r?\n/g).filter(Boolean);
         }
         return this.cache[filePath];
     }
@@ -226,11 +309,13 @@ class IgnoredPaths {
      * add ignore file to node-ignore instance
      * @param {Object} ig, instance of node-ignore
      * @param {string} filePath, file to add to ig
-     * @returns {array} raw ignore rules
+     * @returns {void}
      */
     addIgnoreFile(ig, filePath) {
         ig.ignoreFiles.push(filePath);
-        return ig.add(this.readIgnoreFile(filePath));
+        this
+            .readIgnoreFile(filePath)
+            .forEach(ignoreRule => this.addPatternRelativeToIgnoreFile(ig, ignoreRule));
     }
 
     /**
@@ -243,7 +328,7 @@ class IgnoredPaths {
 
         let result = false;
         const absolutePath = path.resolve(this.options.cwd, filepath);
-        const relativePath = pathUtil.getRelativePath(absolutePath, this.baseDir);
+        const relativePath = pathUtils.getRelativePath(absolutePath, this.getBaseDir());
 
         if (typeof category === "undefined") {
             result = (this.ig.default.filter([relativePath]).length === 0) ||
@@ -251,6 +336,9 @@ class IgnoredPaths {
         } else {
             result = (this.ig[category].filter([relativePath]).length === 0);
         }
+        debug("contains:");
+        debug("  target = %j", filepath);
+        debug("  result = %j", result);
 
         return result;
 
@@ -261,13 +349,15 @@ class IgnoredPaths {
      * @returns {function()} method to check whether a folder should be ignored by glob.
      */
     getIgnoredFoldersGlobChecker() {
+        const baseDir = this.getBaseDir();
+        const ig = ignore();
 
-        const ig = ignore().add(DEFAULT_IGNORE_DIRS);
+        DEFAULT_IGNORE_DIRS.forEach(ignoreDir => this.addPatternRelativeToCwd(ig, ignoreDir));
 
         if (this.options.dotfiles !== true) {
 
             // Ignore hidden folders.  (This cannot be ".*", or else it's not possible to unignore hidden files)
-            ig.add([".*/*", "!../"]);
+            ig.add([".*/*", "!../*"]);
         }
 
         if (this.options.ignore) {
@@ -276,10 +366,8 @@ class IgnoredPaths {
 
         const filter = ig.createFilter();
 
-        const base = this.baseDir;
-
         return function(absolutePath) {
-            const relative = pathUtil.getRelativePath(absolutePath, base);
+            const relative = pathUtils.getRelativePath(absolutePath, baseDir);
 
             if (!relative) {
                 return false;
diff --git a/lib/linter.js b/lib/linter.js
index a6b5a5408..8f7bdf9e4 100644
--- a/lib/linter.js
+++ b/lib/linter.js
@@ -25,7 +25,7 @@ const eslintScope = require("eslint-scope"),
     createReportTranslator = require("./report-translator"),
     Rules = require("./rules"),
     timing = require("./util/timing"),
-    astUtils = require("./ast-utils"),
+    astUtils = require("./util/ast-utils"),
     pkg = require("../package.json"),
     SourceCodeFixer = require("./util/source-code-fixer");
 
diff --git a/lib/rules/.eslintrc.yml b/lib/rules/.eslintrc.yml
deleted file mode 100644
index 64b3cee7f..000000000
--- a/lib/rules/.eslintrc.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-rules:
-    rulesdir/no-invalid-meta: "error"
-    rulesdir/consistent-docs-description: "error"
-    rulesdir/consistent-docs-url: "error"
diff --git a/lib/rules/array-bracket-newline.js b/lib/rules/array-bracket-newline.js
index e19040572..e8f7c502e 100644
--- a/lib/rules/array-bracket-newline.js
+++ b/lib/rules/array-bracket-newline.js
@@ -5,7 +5,7 @@
 
 "use strict";
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/array-bracket-spacing.js b/lib/rules/array-bracket-spacing.js
index c64ff3dc2..f46c3978d 100644
--- a/lib/rules/array-bracket-spacing.js
+++ b/lib/rules/array-bracket-spacing.js
@@ -4,7 +4,7 @@
  */
 "use strict";
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/array-callback-return.js b/lib/rules/array-callback-return.js
index 2375dcba9..4d374cf22 100644
--- a/lib/rules/array-callback-return.js
+++ b/lib/rules/array-callback-return.js
@@ -11,7 +11,7 @@
 
 const lodash = require("lodash");
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Helpers
diff --git a/lib/rules/array-element-newline.js b/lib/rules/array-element-newline.js
index b437c6932..c4caf8c71 100644
--- a/lib/rules/array-element-newline.js
+++ b/lib/rules/array-element-newline.js
@@ -5,7 +5,7 @@
 
 "use strict";
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/arrow-body-style.js b/lib/rules/arrow-body-style.js
index 49feb0670..92068c75c 100644
--- a/lib/rules/arrow-body-style.js
+++ b/lib/rules/arrow-body-style.js
@@ -8,7 +8,7 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/arrow-parens.js b/lib/rules/arrow-parens.js
index 8cabb7f90..7a6ef6f8b 100644
--- a/lib/rules/arrow-parens.js
+++ b/lib/rules/arrow-parens.js
@@ -8,7 +8,7 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/arrow-spacing.js b/lib/rules/arrow-spacing.js
index 52f8fcab9..a1db18fc9 100644
--- a/lib/rules/arrow-spacing.js
+++ b/lib/rules/arrow-spacing.js
@@ -8,7 +8,7 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/block-spacing.js b/lib/rules/block-spacing.js
index 536381362..838c2c701 100644
--- a/lib/rules/block-spacing.js
+++ b/lib/rules/block-spacing.js
@@ -5,7 +5,7 @@
 
 "use strict";
 
-const util = require("../ast-utils");
+const util = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/brace-style.js b/lib/rules/brace-style.js
index e2cbafe21..236a01096 100644
--- a/lib/rules/brace-style.js
+++ b/lib/rules/brace-style.js
@@ -5,7 +5,7 @@
 
 "use strict";
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/capitalized-comments.js b/lib/rules/capitalized-comments.js
index c98a4464a..8fabde287 100644
--- a/lib/rules/capitalized-comments.js
+++ b/lib/rules/capitalized-comments.js
@@ -9,7 +9,7 @@
 //------------------------------------------------------------------------------
 
 const LETTER_PATTERN = require("../util/patterns/letters");
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Helpers
diff --git a/lib/rules/comma-dangle.js b/lib/rules/comma-dangle.js
index 50de7b59b..9bc6c3fa8 100644
--- a/lib/rules/comma-dangle.js
+++ b/lib/rules/comma-dangle.js
@@ -10,7 +10,7 @@
 //------------------------------------------------------------------------------
 
 const lodash = require("lodash");
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Helpers
diff --git a/lib/rules/comma-spacing.js b/lib/rules/comma-spacing.js
index 2a48e54d5..d3f82b3a4 100644
--- a/lib/rules/comma-spacing.js
+++ b/lib/rules/comma-spacing.js
@@ -4,7 +4,7 @@
  */
 "use strict";
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/comma-style.js b/lib/rules/comma-style.js
index aac667f73..bd98d7acc 100644
--- a/lib/rules/comma-style.js
+++ b/lib/rules/comma-style.js
@@ -5,7 +5,7 @@
 
 "use strict";
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/complexity.js b/lib/rules/complexity.js
index 0b8644136..f25194595 100644
--- a/lib/rules/complexity.js
+++ b/lib/rules/complexity.js
@@ -12,7 +12,7 @@
 
 const lodash = require("lodash");
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/computed-property-spacing.js b/lib/rules/computed-property-spacing.js
index 51334a2ab..060b2c5b4 100644
--- a/lib/rules/computed-property-spacing.js
+++ b/lib/rules/computed-property-spacing.js
@@ -4,7 +4,7 @@
  */
 "use strict";
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/consistent-return.js b/lib/rules/consistent-return.js
index c86b1717e..6185d094f 100644
--- a/lib/rules/consistent-return.js
+++ b/lib/rules/consistent-return.js
@@ -10,7 +10,7 @@
 
 const lodash = require("lodash");
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Helpers
diff --git a/lib/rules/curly.js b/lib/rules/curly.js
index 07d991b31..ad8da821c 100644
--- a/lib/rules/curly.js
+++ b/lib/rules/curly.js
@@ -8,7 +8,7 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/dot-location.js b/lib/rules/dot-location.js
index 7ff8ca65a..34d2d4eaa 100644
--- a/lib/rules/dot-location.js
+++ b/lib/rules/dot-location.js
@@ -5,7 +5,7 @@
 
 "use strict";
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/dot-notation.js b/lib/rules/dot-notation.js
index c381661d4..a7062df8a 100644
--- a/lib/rules/dot-notation.js
+++ b/lib/rules/dot-notation.js
@@ -8,7 +8,7 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/eqeqeq.js b/lib/rules/eqeqeq.js
index ec9d0a782..2c5e9ae9e 100644
--- a/lib/rules/eqeqeq.js
+++ b/lib/rules/eqeqeq.js
@@ -9,7 +9,7 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/func-call-spacing.js b/lib/rules/func-call-spacing.js
index b13613cf8..83142bae8 100644
--- a/lib/rules/func-call-spacing.js
+++ b/lib/rules/func-call-spacing.js
@@ -9,7 +9,7 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/func-name-matching.js b/lib/rules/func-name-matching.js
index b71799596..d66f630fc 100644
--- a/lib/rules/func-name-matching.js
+++ b/lib/rules/func-name-matching.js
@@ -9,7 +9,7 @@
 // Requirements
 //--------------------------------------------------------------------------
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 const esutils = require("esutils");
 
 //--------------------------------------------------------------------------
diff --git a/lib/rules/func-names.js b/lib/rules/func-names.js
index 722f276c1..500b95a1c 100644
--- a/lib/rules/func-names.js
+++ b/lib/rules/func-names.js
@@ -9,7 +9,7 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 /**
  * Checks whether or not a given variable is a function name.
diff --git a/lib/rules/function-paren-newline.js b/lib/rules/function-paren-newline.js
index 7e4f2792c..c483e40da 100644
--- a/lib/rules/function-paren-newline.js
+++ b/lib/rules/function-paren-newline.js
@@ -8,7 +8,7 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/getter-return.js b/lib/rules/getter-return.js
index fe40e5f09..8fd9f1599 100644
--- a/lib/rules/getter-return.js
+++ b/lib/rules/getter-return.js
@@ -9,7 +9,7 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Helpers
diff --git a/lib/rules/indent-legacy.js b/lib/rules/indent-legacy.js
index dc6d1689e..e6dc92163 100644
--- a/lib/rules/indent-legacy.js
+++ b/lib/rules/indent-legacy.js
@@ -12,7 +12,7 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/indent.js b/lib/rules/indent.js
index a08b4d7e5..716167d2c 100644
--- a/lib/rules/indent.js
+++ b/lib/rules/indent.js
@@ -1,5 +1,5 @@
 /**
- * @fileoverview This option sets a specific tab width for your code
+ * @fileoverview This rule sets a specific indentation style and width for your code
  *
  * @author Teddy Katz
  * @author Vitaly Puzrin
@@ -13,7 +13,7 @@
 //------------------------------------------------------------------------------
 
 const lodash = require("lodash");
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 const createTree = require("functional-red-black-tree");
 
 //------------------------------------------------------------------------------
@@ -855,7 +855,11 @@ module.exports = {
                         previousElement &&
                         previousElementLastToken.loc.end.line - countTrailingLinebreaks(previousElementLastToken.value) > startToken.loc.end.line
                     ) {
-                        offsets.setDesiredOffsets(element.range, firstTokenOfPreviousElement, 0);
+                        offsets.setDesiredOffsets(
+                            [previousElement.range[1], element.range[1]],
+                            firstTokenOfPreviousElement,
+                            0
+                        );
                     }
                 }
             });
@@ -997,6 +1001,31 @@ module.exports = {
             return !node || node.loc.start.line === token.loc.start.line;
         }
 
+        /**
+         * Check whether there are any blank (whitespace-only) lines between
+         * two tokens on separate lines.
+         * @param {Token} firstToken The first token.
+         * @param {Token} secondToken The second token.
+         * @returns {boolean} `true` if the tokens are on separate lines and
+         *   there exists a blank line between them, `false` otherwise.
+         */
+        function hasBlankLinesBetween(firstToken, secondToken) {
+            const firstTokenLine = firstToken.loc.end.line;
+            const secondTokenLine = secondToken.loc.start.line;
+
+            if (firstTokenLine === secondTokenLine || firstTokenLine === secondTokenLine - 1) {
+                return false;
+            }
+
+            for (let line = firstTokenLine + 1; line < secondTokenLine; ++line) {
+                if (!tokenInfo.firstTokensByLineNumber.has(line)) {
+                    return true;
+                }
+            }
+
+            return false;
+        }
+
         const ignoredNodeFirstTokens = new Set();
 
         const baseOffsetListeners = {
@@ -1536,10 +1565,13 @@ module.exports = {
                             const tokenBefore = precedingTokens.get(firstTokenOfLine);
                             const tokenAfter = tokenBefore ? sourceCode.getTokenAfter(tokenBefore) : sourceCode.ast.tokens[0];
 
+                            const mayAlignWithBefore = tokenBefore && !hasBlankLinesBetween(tokenBefore, firstTokenOfLine);
+                            const mayAlignWithAfter = tokenAfter && !hasBlankLinesBetween(firstTokenOfLine, tokenAfter);
+
                             // If a comment matches the expected indentation of the token immediately before or after, don't report it.
                             if (
-                                tokenBefore && validateTokenIndent(firstTokenOfLine, offsets.getDesiredIndent(tokenBefore)) ||
-                                tokenAfter && validateTokenIndent(firstTokenOfLine, offsets.getDesiredIndent(tokenAfter))
+                                mayAlignWithBefore && validateTokenIndent(firstTokenOfLine, offsets.getDesiredIndent(tokenBefore)) ||
+                                mayAlignWithAfter && validateTokenIndent(firstTokenOfLine, offsets.getDesiredIndent(tokenAfter))
                             ) {
                                 return;
                             }
diff --git a/lib/rules/jsx-quotes.js b/lib/rules/jsx-quotes.js
index 54ec481a8..3dd9567d7 100644
--- a/lib/rules/jsx-quotes.js
+++ b/lib/rules/jsx-quotes.js
@@ -9,7 +9,7 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Constants
diff --git a/lib/rules/key-spacing.js b/lib/rules/key-spacing.js
index e5242ff5b..75578b2c7 100644
--- a/lib/rules/key-spacing.js
+++ b/lib/rules/key-spacing.js
@@ -8,7 +8,7 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Helpers
diff --git a/lib/rules/keyword-spacing.js b/lib/rules/keyword-spacing.js
index a2ce79ab5..2a66779e7 100644
--- a/lib/rules/keyword-spacing.js
+++ b/lib/rules/keyword-spacing.js
@@ -9,7 +9,7 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const astUtils = require("../ast-utils"),
+const astUtils = require("../util/ast-utils"),
     keywords = require("../util/keywords");
 
 //------------------------------------------------------------------------------
diff --git a/lib/rules/line-comment-position.js b/lib/rules/line-comment-position.js
index ebdb024f6..4327e70e1 100644
--- a/lib/rules/line-comment-position.js
+++ b/lib/rules/line-comment-position.js
@@ -4,7 +4,7 @@
  */
 "use strict";
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
@@ -59,7 +59,7 @@ module.exports = {
             above = !options || options === "above";
 
         } else {
-            above = options.position === "above";
+            above = !options.position || options.position === "above";
             ignorePattern = options.ignorePattern;
 
             if (options.hasOwnProperty("applyDefaultIgnorePatterns")) {
diff --git a/lib/rules/linebreak-style.js b/lib/rules/linebreak-style.js
index d5a170f73..cd432dbcc 100644
--- a/lib/rules/linebreak-style.js
+++ b/lib/rules/linebreak-style.js
@@ -9,7 +9,7 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/lines-around-comment.js b/lib/rules/lines-around-comment.js
index 5d98473be..67fd2032b 100644
--- a/lib/rules/lines-around-comment.js
+++ b/lib/rules/lines-around-comment.js
@@ -9,7 +9,7 @@
 //------------------------------------------------------------------------------
 
 const lodash = require("lodash"),
-    astUtils = require("../ast-utils");
+    astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Helpers
diff --git a/lib/rules/lines-around-directive.js b/lib/rules/lines-around-directive.js
index 3ba3ab5bb..e8d613a41 100644
--- a/lib/rules/lines-around-directive.js
+++ b/lib/rules/lines-around-directive.js
@@ -6,7 +6,7 @@
 
 "use strict";
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/lines-between-class-members.js b/lib/rules/lines-between-class-members.js
index 252984da5..8d4e6dd8c 100644
--- a/lib/rules/lines-between-class-members.js
+++ b/lib/rules/lines-between-class-members.js
@@ -4,7 +4,7 @@
  */
 "use strict";
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/max-len.js b/lib/rules/max-len.js
index 273eb8490..88a388309 100644
--- a/lib/rules/max-len.js
+++ b/lib/rules/max-len.js
@@ -266,7 +266,7 @@ module.exports = {
                 // list of comments to ignore
                 comments = ignoreComments || maxCommentLength || ignoreTrailingComments ? sourceCode.getAllComments() : [];
 
-                // we iterate over comments in parallel with the lines
+            // we iterate over comments in parallel with the lines
             let commentsIndex = 0;
 
             const strings = getAllStrings();
diff --git a/lib/rules/max-lines-per-function.js b/lib/rules/max-lines-per-function.js
index b40c7ee88..ccf6304e4 100644
--- a/lib/rules/max-lines-per-function.js
+++ b/lib/rules/max-lines-per-function.js
@@ -8,7 +8,7 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Constants
diff --git a/lib/rules/max-lines.js b/lib/rules/max-lines.js
index 9bb4420ed..e3fccb314 100644
--- a/lib/rules/max-lines.js
+++ b/lib/rules/max-lines.js
@@ -9,7 +9,7 @@
 //------------------------------------------------------------------------------
 
 const lodash = require("lodash");
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/max-params.js b/lib/rules/max-params.js
index d7c22c527..43c649ee8 100644
--- a/lib/rules/max-params.js
+++ b/lib/rules/max-params.js
@@ -11,7 +11,7 @@
 
 const lodash = require("lodash");
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/max-statements-per-line.js b/lib/rules/max-statements-per-line.js
index a6776bdea..566f04ab5 100644
--- a/lib/rules/max-statements-per-line.js
+++ b/lib/rules/max-statements-per-line.js
@@ -8,7 +8,7 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/max-statements.js b/lib/rules/max-statements.js
index faa0d5d84..8501fd688 100644
--- a/lib/rules/max-statements.js
+++ b/lib/rules/max-statements.js
@@ -11,7 +11,7 @@
 
 const lodash = require("lodash");
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/multiline-comment-style.js b/lib/rules/multiline-comment-style.js
index 4da9a619f..5dd39e00a 100644
--- a/lib/rules/multiline-comment-style.js
+++ b/lib/rules/multiline-comment-style.js
@@ -4,7 +4,7 @@
  */
 "use strict";
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/multiline-ternary.js b/lib/rules/multiline-ternary.js
index 10cf269fb..6a22a1113 100644
--- a/lib/rules/multiline-ternary.js
+++ b/lib/rules/multiline-ternary.js
@@ -5,7 +5,7 @@
 
 "use strict";
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/new-parens.js b/lib/rules/new-parens.js
index abf2e032b..fab302000 100644
--- a/lib/rules/new-parens.js
+++ b/lib/rules/new-parens.js
@@ -9,7 +9,7 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Helpers
diff --git a/lib/rules/newline-after-var.js b/lib/rules/newline-after-var.js
index b11d9d995..62ccb3db2 100644
--- a/lib/rules/newline-after-var.js
+++ b/lib/rules/newline-after-var.js
@@ -10,7 +10,7 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/newline-per-chained-call.js b/lib/rules/newline-per-chained-call.js
index 9691da44e..2adcdfe45 100644
--- a/lib/rules/newline-per-chained-call.js
+++ b/lib/rules/newline-per-chained-call.js
@@ -6,7 +6,7 @@
 
 "use strict";
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/no-alert.js b/lib/rules/no-alert.js
index 69d419da1..1c08460f3 100644
--- a/lib/rules/no-alert.js
+++ b/lib/rules/no-alert.js
@@ -8,7 +8,7 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const getPropertyName = require("../ast-utils").getStaticPropertyName;
+const getPropertyName = require("../util/ast-utils").getStaticPropertyName;
 
 //------------------------------------------------------------------------------
 // Helpers
diff --git a/lib/rules/no-async-promise-executor.js b/lib/rules/no-async-promise-executor.js
new file mode 100644
index 000000000..55d489eb6
--- /dev/null
+++ b/lib/rules/no-async-promise-executor.js
@@ -0,0 +1,33 @@
+/**
+ * @fileoverview disallow using an async function as a Promise executor
+ * @author Teddy Katz
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = {
+    meta: {
+        docs: {
+            description: "disallow using an async function as a Promise executor",
+            category: "Possible Errors",
+            recommended: false,
+            url: "https://eslint.org/docs/rules/no-async-promise-executor"
+        },
+        fixable: null,
+        schema: []
+    },
+
+    create(context) {
+        return {
+            "NewExpression[callee.name='Promise'][arguments.0.async=true]"(node) {
+                context.report({
+                    node: context.getSourceCode().getFirstToken(node.arguments[0], token => token.value === "async"),
+                    message: "Promise executor functions should not be async."
+                });
+            }
+        };
+    }
+};
diff --git a/lib/rules/no-catch-shadow.js b/lib/rules/no-catch-shadow.js
index e1e24e0ef..f749490f3 100644
--- a/lib/rules/no-catch-shadow.js
+++ b/lib/rules/no-catch-shadow.js
@@ -10,7 +10,7 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/no-class-assign.js b/lib/rules/no-class-assign.js
index 58dddd6a6..9b28d40d4 100644
--- a/lib/rules/no-class-assign.js
+++ b/lib/rules/no-class-assign.js
@@ -5,7 +5,7 @@
 
 "use strict";
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/no-cond-assign.js b/lib/rules/no-cond-assign.js
index 4c7b5722d..caf9563e9 100644
--- a/lib/rules/no-cond-assign.js
+++ b/lib/rules/no-cond-assign.js
@@ -4,7 +4,7 @@
  */
 "use strict";
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 const NODE_DESCRIPTIONS = {
     DoWhileStatement: "a 'do...while' statement",
diff --git a/lib/rules/no-confusing-arrow.js b/lib/rules/no-confusing-arrow.js
index 297e3b148..503174e9a 100644
--- a/lib/rules/no-confusing-arrow.js
+++ b/lib/rules/no-confusing-arrow.js
@@ -6,7 +6,7 @@
 
 "use strict";
 
-const astUtils = require("../ast-utils.js");
+const astUtils = require("../util/ast-utils.js");
 
 //------------------------------------------------------------------------------
 // Helpers
diff --git a/lib/rules/no-console.js b/lib/rules/no-console.js
index fd5c33a8e..5fb3a159b 100644
--- a/lib/rules/no-console.js
+++ b/lib/rules/no-console.js
@@ -9,7 +9,7 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/no-const-assign.js b/lib/rules/no-const-assign.js
index 043fe05df..3188bd34d 100644
--- a/lib/rules/no-const-assign.js
+++ b/lib/rules/no-const-assign.js
@@ -5,7 +5,7 @@
 
 "use strict";
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/no-dupe-keys.js b/lib/rules/no-dupe-keys.js
index 577710c65..31493bd04 100644
--- a/lib/rules/no-dupe-keys.js
+++ b/lib/rules/no-dupe-keys.js
@@ -9,7 +9,7 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Helpers
diff --git a/lib/rules/no-else-return.js b/lib/rules/no-else-return.js
index 5e58acfe0..1000fa807 100644
--- a/lib/rules/no-else-return.js
+++ b/lib/rules/no-else-return.js
@@ -9,7 +9,7 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 const FixTracker = require("../util/fix-tracker");
 
 //------------------------------------------------------------------------------
diff --git a/lib/rules/no-empty-function.js b/lib/rules/no-empty-function.js
index d9948cd4a..c8039314a 100644
--- a/lib/rules/no-empty-function.js
+++ b/lib/rules/no-empty-function.js
@@ -9,7 +9,7 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Helpers
diff --git a/lib/rules/no-empty.js b/lib/rules/no-empty.js
index a598d40f8..2f4c258a2 100644
--- a/lib/rules/no-empty.js
+++ b/lib/rules/no-empty.js
@@ -8,7 +8,7 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/no-eval.js b/lib/rules/no-eval.js
index 68ed086a3..c3ea87d46 100644
--- a/lib/rules/no-eval.js
+++ b/lib/rules/no-eval.js
@@ -9,7 +9,7 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Helpers
diff --git a/lib/rules/no-ex-assign.js b/lib/rules/no-ex-assign.js
index feace415e..1c7beccf8 100644
--- a/lib/rules/no-ex-assign.js
+++ b/lib/rules/no-ex-assign.js
@@ -5,7 +5,7 @@
 
 "use strict";
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/no-extend-native.js b/lib/rules/no-extend-native.js
index 3ba13090a..a1bf49f13 100644
--- a/lib/rules/no-extend-native.js
+++ b/lib/rules/no-extend-native.js
@@ -9,7 +9,7 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 const globals = require("globals");
 
 //------------------------------------------------------------------------------
diff --git a/lib/rules/no-extra-bind.js b/lib/rules/no-extra-bind.js
index 8d901808f..b8376adfc 100644
--- a/lib/rules/no-extra-bind.js
+++ b/lib/rules/no-extra-bind.js
@@ -8,7 +8,7 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/no-extra-boolean-cast.js b/lib/rules/no-extra-boolean-cast.js
index 381913617..5eac6b53f 100644
--- a/lib/rules/no-extra-boolean-cast.js
+++ b/lib/rules/no-extra-boolean-cast.js
@@ -9,7 +9,7 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/no-extra-label.js b/lib/rules/no-extra-label.js
index 73a3fea9c..9310e90f7 100644
--- a/lib/rules/no-extra-label.js
+++ b/lib/rules/no-extra-label.js
@@ -9,7 +9,7 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/no-extra-parens.js b/lib/rules/no-extra-parens.js
index 3d4ee19e8..814cf0faf 100644
--- a/lib/rules/no-extra-parens.js
+++ b/lib/rules/no-extra-parens.js
@@ -8,7 +8,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
-const astUtils = require("../ast-utils.js");
+const astUtils = require("../util/ast-utils.js");
 
 module.exports = {
     meta: {
diff --git a/lib/rules/no-extra-semi.js b/lib/rules/no-extra-semi.js
index a07410885..4d40b5e15 100644
--- a/lib/rules/no-extra-semi.js
+++ b/lib/rules/no-extra-semi.js
@@ -10,7 +10,7 @@
 //------------------------------------------------------------------------------
 
 const FixTracker = require("../util/fix-tracker");
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/no-floating-decimal.js b/lib/rules/no-floating-decimal.js
index da8c47912..a62846cc1 100644
--- a/lib/rules/no-floating-decimal.js
+++ b/lib/rules/no-floating-decimal.js
@@ -9,7 +9,7 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/no-func-assign.js b/lib/rules/no-func-assign.js
index a0a17f369..029f6a9d7 100644
--- a/lib/rules/no-func-assign.js
+++ b/lib/rules/no-func-assign.js
@@ -5,7 +5,7 @@
 
 "use strict";
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/no-implicit-coercion.js b/lib/rules/no-implicit-coercion.js
index 1dd4d431d..3bfe3f0d3 100644
--- a/lib/rules/no-implicit-coercion.js
+++ b/lib/rules/no-implicit-coercion.js
@@ -5,7 +5,7 @@
 
 "use strict";
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Helpers
diff --git a/lib/rules/no-inline-comments.js b/lib/rules/no-inline-comments.js
index 85a0d3831..2fb219092 100644
--- a/lib/rules/no-inline-comments.js
+++ b/lib/rules/no-inline-comments.js
@@ -4,7 +4,7 @@
  */
 "use strict";
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/no-invalid-this.js b/lib/rules/no-invalid-this.js
index a04673be8..480deebc1 100644
--- a/lib/rules/no-invalid-this.js
+++ b/lib/rules/no-invalid-this.js
@@ -9,7 +9,7 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/no-irregular-whitespace.js b/lib/rules/no-irregular-whitespace.js
index 7f9adc10a..729f829a1 100644
--- a/lib/rules/no-irregular-whitespace.js
+++ b/lib/rules/no-irregular-whitespace.js
@@ -10,7 +10,7 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Constants
diff --git a/lib/rules/no-label-var.js b/lib/rules/no-label-var.js
index a880abfca..3f5aba4fc 100644
--- a/lib/rules/no-label-var.js
+++ b/lib/rules/no-label-var.js
@@ -9,7 +9,7 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/no-labels.js b/lib/rules/no-labels.js
index e09bb7b6e..bd6ec57a3 100644
--- a/lib/rules/no-labels.js
+++ b/lib/rules/no-labels.js
@@ -8,7 +8,7 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/no-misleading-character-class.js b/lib/rules/no-misleading-character-class.js
new file mode 100644
index 000000000..e410efed9
--- /dev/null
+++ b/lib/rules/no-misleading-character-class.js
@@ -0,0 +1,189 @@
+/**
+ * @author Toru Nagashima <https://github.com/mysticatea>
+ */
+"use strict";
+
+const { CALL, CONSTRUCT, ReferenceTracker, getStringIfConstant } = require("eslint-utils");
+const { RegExpParser, visitRegExpAST } = require("regexpp");
+const { isCombiningCharacter, isEmojiModifier, isRegionalIndicatorSymbol, isSurrogatePair } = require("../util/unicode");
+
+//------------------------------------------------------------------------------
+// Helpers
+//------------------------------------------------------------------------------
+
+/**
+ * Iterate character sequences of a given nodes.
+ *
+ * CharacterClassRange syntax can steal a part of character sequence,
+ * so this function reverts CharacterClassRange syntax and restore the sequence.
+ *
+ * @param {regexpp.AST.CharacterClassElement[]} nodes The node list to iterate character sequences.
+ * @returns {IterableIterator<number[]>} The list of character sequences.
+ */
+function *iterateCharacterSequence(nodes) {
+    let seq = [];
+
+    for (const node of nodes) {
+        switch (node.type) {
+            case "Character":
+                seq.push(node.value);
+                break;
+
+            case "CharacterClassRange":
+                seq.push(node.min.value);
+                yield seq;
+                seq = [node.max.value];
+                break;
+
+            case "CharacterSet":
+                if (seq.length > 0) {
+                    yield seq;
+                    seq = [];
+                }
+                break;
+
+            // no default
+        }
+    }
+
+    if (seq.length > 0) {
+        yield seq;
+    }
+}
+
+const hasCharacterSequence = {
+    surrogatePairWithoutUFlag(chars) {
+        return chars.some((c, i) => i !== 0 && isSurrogatePair(chars[i - 1], c));
+    },
+
+    combiningClass(chars) {
+        return chars.some((c, i) => (
+            i !== 0 &&
+            isCombiningCharacter(c) &&
+            !isCombiningCharacter(chars[i - 1])
+        ));
+    },
+
+    emojiModifier(chars) {
+        return chars.some((c, i) => (
+            i !== 0 &&
+            isEmojiModifier(c) &&
+            !isEmojiModifier(chars[i - 1])
+        ));
+    },
+
+    regionalIndicatorSymbol(chars) {
+        return chars.some((c, i) => (
+            i !== 0 &&
+            isRegionalIndicatorSymbol(c) &&
+            isRegionalIndicatorSymbol(chars[i - 1])
+        ));
+    },
+
+    zwj(chars) {
+        const lastIndex = chars.length - 1;
+
+        return chars.some((c, i) => (
+            i !== 0 &&
+            i !== lastIndex &&
+            c === 0x200d &&
+            chars[i - 1] !== 0x200d &&
+            chars[i + 1] !== 0x200d
+        ));
+    }
+};
+
+const kinds = Object.keys(hasCharacterSequence);
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = {
+    meta: {
+        docs: {
+            description: "disallow characters which are made with multiple code points in character class syntax",
+            category: "Possible Errors",
+            recommended: false,
+            url: "https://eslint.org/docs/rules/no-misleading-character-class"
+        },
+        schema: [],
+        messages: {
+            surrogatePairWithoutUFlag: "Unexpected surrogate pair in character class. Use 'u' flag.",
+            combiningClass: "Unexpected combined character in character class.",
+            emojiModifier: "Unexpected modified Emoji in character class.",
+            regionalIndicatorSymbol: "Unexpected national flag in character class.",
+            zwj: "Unexpected joined character sequence in character class."
+        }
+    },
+    create(context) {
+        const parser = new RegExpParser();
+
+        /**
+         * Verify a given regular expression.
+         * @param {Node} node The node to report.
+         * @param {string} pattern The regular expression pattern to verify.
+         * @param {string} flags The flags of the regular expression.
+         * @returns {void}
+         */
+        function verify(node, pattern, flags) {
+            const patternNode = parser.parsePattern(
+                pattern,
+                0,
+                pattern.length,
+                flags.includes("u")
+            );
+            const has = {
+                surrogatePairWithoutUFlag: false,
+                combiningClass: false,
+                variationSelector: false,
+                emojiModifier: false,
+                regionalIndicatorSymbol: false,
+                zwj: false
+            };
+
+            visitRegExpAST(patternNode, {
+                onCharacterClassEnter(ccNode) {
+                    for (const chars of iterateCharacterSequence(ccNode.elements)) {
+                        for (const kind of kinds) {
+                            has[kind] = has[kind] || hasCharacterSequence[kind](chars);
+                        }
+                    }
+                }
+            });
+
+            for (const kind of kinds) {
+                if (has[kind]) {
+                    context.report({ node, messageId: kind });
+                }
+            }
+        }
+
+        return {
+            "Literal[regex]"(node) {
+                verify(node, node.regex.pattern, node.regex.flags);
+            },
+            "Program"() {
+                const scope = context.getScope();
+                const tracker = new ReferenceTracker(scope);
+
+                /*
+                 * Iterate calls of RegExp.
+                 * E.g., `new RegExp()`, `RegExp()`, `new window.RegExp()`,
+                 *       `const {RegExp: a} = window; new a()`, etc...
+                 */
+                for (const { node } of tracker.iterateGlobalReferences({
+                    RegExp: { [CALL]: true, [CONSTRUCT]: true }
+                })) {
+                    const [patternNode, flagsNode] = node.arguments;
+                    const pattern = getStringIfConstant(patternNode, scope);
+                    const flags = getStringIfConstant(flagsNode, scope);
+
+                    if (typeof pattern === "string") {
+                        verify(node, pattern, flags || "");
+                    }
+                }
+            }
+        };
+    }
+};
diff --git a/lib/rules/no-mixed-operators.js b/lib/rules/no-mixed-operators.js
index 0df42259d..d4ead2006 100644
--- a/lib/rules/no-mixed-operators.js
+++ b/lib/rules/no-mixed-operators.js
@@ -9,7 +9,7 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const astUtils = require("../ast-utils.js");
+const astUtils = require("../util/ast-utils.js");
 
 //------------------------------------------------------------------------------
 // Helpers
diff --git a/lib/rules/no-multi-spaces.js b/lib/rules/no-multi-spaces.js
index d0ca097ad..41bcd4fb6 100644
--- a/lib/rules/no-multi-spaces.js
+++ b/lib/rules/no-multi-spaces.js
@@ -5,7 +5,7 @@
 
 "use strict";
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/no-multi-str.js b/lib/rules/no-multi-str.js
index 2b97c261e..ee0aaaa4c 100644
--- a/lib/rules/no-multi-str.js
+++ b/lib/rules/no-multi-str.js
@@ -9,7 +9,7 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/no-regex-spaces.js b/lib/rules/no-regex-spaces.js
index a50692a4c..089e06028 100644
--- a/lib/rules/no-regex-spaces.js
+++ b/lib/rules/no-regex-spaces.js
@@ -5,7 +5,7 @@
 
 "use strict";
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/no-restricted-properties.js b/lib/rules/no-restricted-properties.js
index 71cc83c65..c0f1cfb6d 100644
--- a/lib/rules/no-restricted-properties.js
+++ b/lib/rules/no-restricted-properties.js
@@ -5,7 +5,7 @@
 
 "use strict";
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/no-return-assign.js b/lib/rules/no-return-assign.js
index ca96da9f2..519f9e0d0 100644
--- a/lib/rules/no-return-assign.js
+++ b/lib/rules/no-return-assign.js
@@ -8,7 +8,7 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Helpers
diff --git a/lib/rules/no-return-await.js b/lib/rules/no-return-await.js
index fc3373d3c..5f531a183 100644
--- a/lib/rules/no-return-await.js
+++ b/lib/rules/no-return-await.js
@@ -4,7 +4,7 @@
  */
 "use strict";
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/no-self-assign.js b/lib/rules/no-self-assign.js
index 5b65ea4f9..87d1f2ff4 100644
--- a/lib/rules/no-self-assign.js
+++ b/lib/rules/no-self-assign.js
@@ -9,7 +9,7 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Helpers
diff --git a/lib/rules/no-sequences.js b/lib/rules/no-sequences.js
index 8eaf55572..e74943d81 100644
--- a/lib/rules/no-sequences.js
+++ b/lib/rules/no-sequences.js
@@ -9,7 +9,7 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/no-shadow.js b/lib/rules/no-shadow.js
index 17ca1291d..955fc05e5 100644
--- a/lib/rules/no-shadow.js
+++ b/lib/rules/no-shadow.js
@@ -9,7 +9,7 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/no-this-before-super.js b/lib/rules/no-this-before-super.js
index 944a32352..8a489879e 100644
--- a/lib/rules/no-this-before-super.js
+++ b/lib/rules/no-this-before-super.js
@@ -9,7 +9,7 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Helpers
diff --git a/lib/rules/no-throw-literal.js b/lib/rules/no-throw-literal.js
index b080578bf..301354b6b 100644
--- a/lib/rules/no-throw-literal.js
+++ b/lib/rules/no-throw-literal.js
@@ -5,7 +5,7 @@
 
 "use strict";
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/no-trailing-spaces.js b/lib/rules/no-trailing-spaces.js
index 4d70c3b5c..cca7af2aa 100644
--- a/lib/rules/no-trailing-spaces.js
+++ b/lib/rules/no-trailing-spaces.js
@@ -8,7 +8,7 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/no-undef-init.js b/lib/rules/no-undef-init.js
index 2e0ab2462..f00b05d4f 100644
--- a/lib/rules/no-undef-init.js
+++ b/lib/rules/no-undef-init.js
@@ -5,7 +5,7 @@
 
 "use strict";
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/no-unexpected-multiline.js b/lib/rules/no-unexpected-multiline.js
index 51ba7cfa7..181a00b2d 100644
--- a/lib/rules/no-unexpected-multiline.js
+++ b/lib/rules/no-unexpected-multiline.js
@@ -8,7 +8,7 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/no-unmodified-loop-condition.js b/lib/rules/no-unmodified-loop-condition.js
index a02366bad..fecd8ba5c 100644
--- a/lib/rules/no-unmodified-loop-condition.js
+++ b/lib/rules/no-unmodified-loop-condition.js
@@ -10,7 +10,7 @@
 //------------------------------------------------------------------------------
 
 const Traverser = require("../util/traverser"),
-    astUtils = require("../ast-utils");
+    astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Helpers
diff --git a/lib/rules/no-unneeded-ternary.js b/lib/rules/no-unneeded-ternary.js
index b56ad038a..6b58b018d 100644
--- a/lib/rules/no-unneeded-ternary.js
+++ b/lib/rules/no-unneeded-ternary.js
@@ -5,7 +5,7 @@
 
 "use strict";
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 // Operators that always result in a boolean value
 const BOOLEAN_OPERATORS = new Set(["==", "===", "!=", "!==", ">", ">=", "<", "<=", "in", "instanceof"]);
diff --git a/lib/rules/no-unsafe-negation.js b/lib/rules/no-unsafe-negation.js
index 5dc39f183..b04f80106 100644
--- a/lib/rules/no-unsafe-negation.js
+++ b/lib/rules/no-unsafe-negation.js
@@ -9,7 +9,7 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Helpers
diff --git a/lib/rules/no-unused-vars.js b/lib/rules/no-unused-vars.js
index 0d5194bc8..fff3e33d9 100644
--- a/lib/rules/no-unused-vars.js
+++ b/lib/rules/no-unused-vars.js
@@ -10,7 +10,7 @@
 //------------------------------------------------------------------------------
 
 const lodash = require("lodash");
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/no-useless-call.js b/lib/rules/no-useless-call.js
index 925c9f79a..0778b374f 100644
--- a/lib/rules/no-useless-call.js
+++ b/lib/rules/no-useless-call.js
@@ -5,7 +5,7 @@
 
 "use strict";
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Helpers
diff --git a/lib/rules/no-useless-computed-key.js b/lib/rules/no-useless-computed-key.js
index 07573075e..189f50853 100644
--- a/lib/rules/no-useless-computed-key.js
+++ b/lib/rules/no-useless-computed-key.js
@@ -8,7 +8,7 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/no-useless-concat.js b/lib/rules/no-useless-concat.js
index a9ac78684..e8e36aa1c 100644
--- a/lib/rules/no-useless-concat.js
+++ b/lib/rules/no-useless-concat.js
@@ -8,7 +8,7 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Helpers
diff --git a/lib/rules/no-useless-escape.js b/lib/rules/no-useless-escape.js
index 2ddab7854..7f4b87ed9 100644
--- a/lib/rules/no-useless-escape.js
+++ b/lib/rules/no-useless-escape.js
@@ -5,7 +5,7 @@
 
 "use strict";
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/no-useless-return.js b/lib/rules/no-useless-return.js
index 731ca4dff..b5b8ebc32 100644
--- a/lib/rules/no-useless-return.js
+++ b/lib/rules/no-useless-return.js
@@ -8,7 +8,7 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const astUtils = require("../ast-utils"),
+const astUtils = require("../util/ast-utils"),
     FixTracker = require("../util/fix-tracker");
 
 //------------------------------------------------------------------------------
diff --git a/lib/rules/no-var.js b/lib/rules/no-var.js
index 5ca868e65..2c32a023d 100644
--- a/lib/rules/no-var.js
+++ b/lib/rules/no-var.js
@@ -9,7 +9,7 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Helpers
diff --git a/lib/rules/no-warning-comments.js b/lib/rules/no-warning-comments.js
index 4e05cc411..5ff76e3a3 100644
--- a/lib/rules/no-warning-comments.js
+++ b/lib/rules/no-warning-comments.js
@@ -5,7 +5,7 @@
 
 "use strict";
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/no-whitespace-before-property.js b/lib/rules/no-whitespace-before-property.js
index fc4c25f84..4b71a9ec1 100644
--- a/lib/rules/no-whitespace-before-property.js
+++ b/lib/rules/no-whitespace-before-property.js
@@ -8,7 +8,7 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/object-curly-newline.js b/lib/rules/object-curly-newline.js
index e979b5ffe..494e78cff 100644
--- a/lib/rules/object-curly-newline.js
+++ b/lib/rules/object-curly-newline.js
@@ -9,7 +9,7 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 const lodash = require("lodash");
 
 //------------------------------------------------------------------------------
diff --git a/lib/rules/object-curly-spacing.js b/lib/rules/object-curly-spacing.js
index b37d6fd90..e7c847a6a 100644
--- a/lib/rules/object-curly-spacing.js
+++ b/lib/rules/object-curly-spacing.js
@@ -4,7 +4,7 @@
  */
 "use strict";
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/object-shorthand.js b/lib/rules/object-shorthand.js
index 71a320a0e..21f039f8b 100644
--- a/lib/rules/object-shorthand.js
+++ b/lib/rules/object-shorthand.js
@@ -17,7 +17,7 @@ const OPTIONS = {
 //------------------------------------------------------------------------------
 // Requirements
 //------------------------------------------------------------------------------
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/operator-assignment.js b/lib/rules/operator-assignment.js
index ad516bbfc..8e4b7025e 100644
--- a/lib/rules/operator-assignment.js
+++ b/lib/rules/operator-assignment.js
@@ -8,7 +8,7 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Helpers
diff --git a/lib/rules/operator-linebreak.js b/lib/rules/operator-linebreak.js
index 558258b27..be2709a1b 100644
--- a/lib/rules/operator-linebreak.js
+++ b/lib/rules/operator-linebreak.js
@@ -9,7 +9,7 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/padding-line-between-statements.js b/lib/rules/padding-line-between-statements.js
index d2254fa6a..f571e1e2e 100644
--- a/lib/rules/padding-line-between-statements.js
+++ b/lib/rules/padding-line-between-statements.js
@@ -9,7 +9,7 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Helpers
@@ -367,6 +367,7 @@ const StatementTypes = {
 
     block: newNodeTypeTester("BlockStatement"),
     empty: newNodeTypeTester("EmptyStatement"),
+    function: newNodeTypeTester("FunctionDeclaration"),
 
     break: newKeywordTester("break"),
     case: newKeywordTester("case"),
@@ -378,7 +379,6 @@ const StatementTypes = {
     do: newKeywordTester("do"),
     export: newKeywordTester("export"),
     for: newKeywordTester("for"),
-    function: newKeywordTester("function"),
     if: newKeywordTester("if"),
     import: newKeywordTester("import"),
     let: newKeywordTester("let"),
diff --git a/lib/rules/prefer-const.js b/lib/rules/prefer-const.js
index a70c98554..774fcf064 100644
--- a/lib/rules/prefer-const.js
+++ b/lib/rules/prefer-const.js
@@ -5,7 +5,7 @@
 
 "use strict";
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Helpers
diff --git a/lib/rules/prefer-object-spread.js b/lib/rules/prefer-object-spread.js
index 3df16b7ae..8e54de249 100644
--- a/lib/rules/prefer-object-spread.js
+++ b/lib/rules/prefer-object-spread.js
@@ -12,7 +12,7 @@ const {
     isOpeningParenToken,
     isClosingParenToken,
     isParenthesised
-} = require("../ast-utils");
+} = require("../util/ast-utils");
 
 const ANY_SPACE = /\s/;
 
diff --git a/lib/rules/prefer-promise-reject-errors.js b/lib/rules/prefer-promise-reject-errors.js
index f92bd58d2..e3d298a74 100644
--- a/lib/rules/prefer-promise-reject-errors.js
+++ b/lib/rules/prefer-promise-reject-errors.js
@@ -4,7 +4,7 @@
  */
 "use strict";
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/prefer-spread.js b/lib/rules/prefer-spread.js
index 62cfb28e7..9bf69c80f 100644
--- a/lib/rules/prefer-spread.js
+++ b/lib/rules/prefer-spread.js
@@ -5,7 +5,7 @@
 
 "use strict";
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Helpers
diff --git a/lib/rules/prefer-template.js b/lib/rules/prefer-template.js
index 14c419942..0471d61ca 100644
--- a/lib/rules/prefer-template.js
+++ b/lib/rules/prefer-template.js
@@ -9,7 +9,7 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Helpers
diff --git a/lib/rules/quotes.js b/lib/rules/quotes.js
index 78794e72b..8dd61c3e3 100644
--- a/lib/rules/quotes.js
+++ b/lib/rules/quotes.js
@@ -9,7 +9,7 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Constants
diff --git a/lib/rules/radix.js b/lib/rules/radix.js
index 7e116a6fb..f71220beb 100644
--- a/lib/rules/radix.js
+++ b/lib/rules/radix.js
@@ -9,7 +9,7 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Helpers
diff --git a/lib/rules/require-atomic-updates.js b/lib/rules/require-atomic-updates.js
new file mode 100644
index 000000000..5d7d71514
--- /dev/null
+++ b/lib/rules/require-atomic-updates.js
@@ -0,0 +1,239 @@
+/**
+ * @fileoverview disallow assignments that can lead to race conditions due to usage of `await` or `yield`
+ * @author Teddy Katz
+ */
+"use strict";
+
+const astUtils = require("../util/ast-utils");
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = {
+    meta: {
+        docs: {
+            description: "disallow assignments that can lead to race conditions due to usage of `await` or `yield`",
+            category: "Possible Errors",
+            recommended: false,
+            url: "https://eslint.org/docs/rules/require-atomic-updates"
+        },
+        fixable: null,
+        schema: [],
+        messages: {
+            nonAtomicUpdate: "Possible race condition: `{{value}}` might be reassigned based on an outdated value of `{{value}}`."
+        }
+    },
+
+    create(context) {
+        const sourceCode = context.getSourceCode();
+        const identifierToSurroundingFunctionMap = new WeakMap();
+        const expressionsByCodePathSegment = new Map();
+
+        //----------------------------------------------------------------------
+        // Helpers
+        //----------------------------------------------------------------------
+
+        const resolvedVariableCache = new WeakMap();
+
+        /**
+         * Gets the variable scope around this variable reference
+         * @param {ASTNode} identifier An `Identifier` AST node
+         * @returns {Scope|null} An escope Scope
+         */
+        function getScope(identifier) {
+            for (let currentNode = identifier; currentNode; currentNode = currentNode.parent) {
+                const scope = sourceCode.scopeManager.acquire(currentNode, true);
+
+                if (scope) {
+                    return scope;
+                }
+            }
+            return null;
+        }
+
+        /**
+         * Resolves a given identifier to a given scope
+         * @param {ASTNode} identifier An `Identifier` AST node
+         * @param {Scope} scope An escope Scope
+         * @returns {Variable|null} An escope Variable corresponding to the given identifier
+         */
+        function resolveVariableInScope(identifier, scope) {
+            return scope.variables.find(variable => variable.name === identifier.name) ||
+                (scope.upper ? resolveVariableInScope(identifier, scope.upper) : null);
+        }
+
+        /**
+         * Resolves an identifier to a variable
+         * @param {ASTNode} identifier An identifier node
+         * @returns {Variable|null} The escope Variable that uses this identifier
+         */
+        function resolveVariable(identifier) {
+            if (!resolvedVariableCache.has(identifier)) {
+                const surroundingScope = getScope(identifier);
+
+                if (surroundingScope) {
+                    resolvedVariableCache.set(identifier, resolveVariableInScope(identifier, surroundingScope));
+                } else {
+                    resolvedVariableCache.set(identifier, null);
+                }
+            }
+
+            return resolvedVariableCache.get(identifier);
+        }
+
+        /**
+         * Checks if an expression is a variable that can only be observed within the given function.
+         * @param {ASTNode} expression The expression to check
+         * @param {ASTNode} surroundingFunction The function node
+         * @returns {boolean} `true` if the expression is a variable which is local to the given function, and is never
+         * referenced in a closure.
+         */
+        function isLocalVariableWithoutEscape(expression, surroundingFunction) {
+            if (expression.type !== "Identifier") {
+                return false;
+            }
+
+            const variable = resolveVariable(expression);
+
+            if (!variable) {
+                return false;
+            }
+
+            return variable.references.every(reference => identifierToSurroundingFunctionMap.get(reference.identifier) === surroundingFunction) &&
+                variable.defs.every(def => identifierToSurroundingFunctionMap.get(def.name) === surroundingFunction);
+        }
+
+        /**
+         * Reports an AssignmentExpression node that has a non-atomic update
+         * @param {ASTNode} assignmentExpression The assignment that is potentially unsafe
+         * @returns {void}
+         */
+        function reportAssignment(assignmentExpression) {
+            context.report({
+                node: assignmentExpression,
+                messageId: "nonAtomicUpdate",
+                data: {
+                    value: sourceCode.getText(assignmentExpression.left)
+                }
+            });
+        }
+
+        /**
+         * If the control flow graph of a function enters an assignment expression, then does the
+         * both of the following steps in order (possibly with other steps in between) before exiting the
+         * assignment expression, then the assignment might be using an outdated value.
+         * 1. Enters a read of the variable or property assigned in the expression (not necessary if operator assignment is used)
+         * 2. Exits an `await` or `yield` expression
+         *
+         * This function checks for the outdated values and reports them.
+         * @param {CodePathSegment} codePathSegment The current code path segment to traverse
+         * @param {ASTNode} surroundingFunction The function node containing the code path segment
+         * @returns {void}
+         */
+        function findOutdatedReads(
+            codePathSegment,
+            surroundingFunction,
+            {
+                seenSegments = new Set(),
+                openAssignmentsWithoutReads = new Set(),
+                openAssignmentsWithReads = new Set()
+            } = {}
+        ) {
+            if (seenSegments.has(codePathSegment)) {
+
+                // An AssignmentExpression can't contain loops, so it's not necessary to reenter them with new state.
+                return;
+            }
+
+            expressionsByCodePathSegment.get(codePathSegment).forEach(({ entering, node }) => {
+                if (node.type === "AssignmentExpression") {
+                    if (entering) {
+                        (node.operator === "=" ? openAssignmentsWithoutReads : openAssignmentsWithReads).add(node);
+                    } else {
+                        openAssignmentsWithoutReads.delete(node);
+                        openAssignmentsWithReads.delete(node);
+                    }
+                } else if (!entering && (node.type === "AwaitExpression" || node.type === "YieldExpression")) {
+                    [...openAssignmentsWithReads]
+                        .filter(assignment => !isLocalVariableWithoutEscape(assignment.left, surroundingFunction))
+                        .forEach(reportAssignment);
+
+                    openAssignmentsWithReads.clear();
+                } else if (!entering && (node.type === "Identifier" || node.type === "MemberExpression")) {
+                    [...openAssignmentsWithoutReads]
+                        .filter(assignment => (
+                            assignment.left !== node &&
+                            assignment.left.type === node.type &&
+                            astUtils.equalTokens(assignment.left, node, sourceCode)
+                        ))
+                        .forEach(assignment => {
+                            openAssignmentsWithoutReads.delete(assignment);
+                            openAssignmentsWithReads.add(assignment);
+                        });
+                }
+            });
+
+            codePathSegment.nextSegments.forEach(nextSegment => {
+                findOutdatedReads(
+                    nextSegment,
+                    surroundingFunction,
+                    {
+                        seenSegments: new Set(seenSegments).add(codePathSegment),
+                        openAssignmentsWithoutReads: new Set(openAssignmentsWithoutReads),
+                        openAssignmentsWithReads: new Set(openAssignmentsWithReads)
+                    }
+                );
+            });
+        }
+
+        //----------------------------------------------------------------------
+        // Public
+        //----------------------------------------------------------------------
+
+        const currentCodePathSegmentStack = [];
+        let currentCodePathSegment = null;
+        const functionStack = [];
+
+        return {
+            onCodePathStart() {
+                currentCodePathSegmentStack.push(currentCodePathSegment);
+            },
+
+            onCodePathEnd(codePath, node) {
+                currentCodePathSegment = currentCodePathSegmentStack.pop();
+
+                if (astUtils.isFunction(node) && (node.async || node.generator)) {
+                    findOutdatedReads(codePath.initialSegment, node);
+                }
+            },
+
+            onCodePathSegmentStart(segment) {
+                currentCodePathSegment = segment;
+                expressionsByCodePathSegment.set(segment, []);
+            },
+
+            "AssignmentExpression, Identifier, MemberExpression, AwaitExpression, YieldExpression"(node) {
+                expressionsByCodePathSegment.get(currentCodePathSegment).push({ entering: true, node });
+            },
+
+            "AssignmentExpression, Identifier, MemberExpression, AwaitExpression, YieldExpression:exit"(node) {
+                expressionsByCodePathSegment.get(currentCodePathSegment).push({ entering: false, node });
+            },
+
+            ":function"(node) {
+                functionStack.push(node);
+            },
+
+            ":function:exit"() {
+                functionStack.pop();
+            },
+
+            Identifier(node) {
+                if (functionStack.length) {
+                    identifierToSurroundingFunctionMap.set(node, functionStack[functionStack.length - 1]);
+                }
+            }
+        };
+    }
+};
diff --git a/lib/rules/require-await.js b/lib/rules/require-await.js
index 5517cf867..de39f372f 100644
--- a/lib/rules/require-await.js
+++ b/lib/rules/require-await.js
@@ -9,7 +9,7 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Helpers
diff --git a/lib/rules/require-unicode-regexp.js b/lib/rules/require-unicode-regexp.js
new file mode 100644
index 000000000..55ca4ff89
--- /dev/null
+++ b/lib/rules/require-unicode-regexp.js
@@ -0,0 +1,65 @@
+/**
+ * @fileoverview Rule to enforce the use of `u` flag on RegExp.
+ * @author Toru Nagashima
+ */
+
+"use strict";
+
+//------------------------------------------------------------------------------
+// Requirements
+//------------------------------------------------------------------------------
+
+const {
+    CALL,
+    CONSTRUCT,
+    ReferenceTracker,
+    getStringIfConstant
+} = require("eslint-utils");
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = {
+    meta: {
+        docs: {
+            description: "enforce the use of `u` flag on RegExp",
+            category: "Best Practices",
+            recommended: false,
+            url: "https://eslint.org/docs/rules/require-unicode-regexp"
+        },
+        messages: {
+            requireUFlag: "Use the 'u' flag."
+        },
+        schema: []
+    },
+
+    create(context) {
+        return {
+            "Literal[regex]"(node) {
+                const flags = node.regex.flags || "";
+
+                if (!flags.includes("u")) {
+                    context.report({ node, messageId: "requireUFlag" });
+                }
+            },
+
+            Program() {
+                const scope = context.getScope();
+                const tracker = new ReferenceTracker(scope);
+                const trackMap = {
+                    RegExp: { [CALL]: true, [CONSTRUCT]: true }
+                };
+
+                for (const { node } of tracker.iterateGlobalReferences(trackMap)) {
+                    const flagsNode = node.arguments[1];
+                    const flags = getStringIfConstant(flagsNode, scope);
+
+                    if (!flagsNode || (typeof flags === "string" && !flags.includes("u"))) {
+                        context.report({ node, messageId: "requireUFlag" });
+                    }
+                }
+            }
+        };
+    }
+};
diff --git a/lib/rules/semi-spacing.js b/lib/rules/semi-spacing.js
index 07af99376..cde93abf3 100644
--- a/lib/rules/semi-spacing.js
+++ b/lib/rules/semi-spacing.js
@@ -5,7 +5,7 @@
 
 "use strict";
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/semi-style.js b/lib/rules/semi-style.js
index de6592813..34899bb54 100644
--- a/lib/rules/semi-style.js
+++ b/lib/rules/semi-style.js
@@ -9,7 +9,7 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/semi.js b/lib/rules/semi.js
index 33a214db7..129d10641 100644
--- a/lib/rules/semi.js
+++ b/lib/rules/semi.js
@@ -9,7 +9,7 @@
 //------------------------------------------------------------------------------
 
 const FixTracker = require("../util/fix-tracker");
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/sort-keys.js b/lib/rules/sort-keys.js
index 85bfe56d5..6e538f732 100644
--- a/lib/rules/sort-keys.js
+++ b/lib/rules/sort-keys.js
@@ -9,7 +9,7 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const astUtils = require("../ast-utils"),
+const astUtils = require("../util/ast-utils"),
     naturalCompare = require("natural-compare");
 
 //------------------------------------------------------------------------------
diff --git a/lib/rules/space-before-blocks.js b/lib/rules/space-before-blocks.js
index 2b82066d7..4f22ae6b6 100644
--- a/lib/rules/space-before-blocks.js
+++ b/lib/rules/space-before-blocks.js
@@ -5,7 +5,7 @@
 
 "use strict";
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/space-before-function-paren.js b/lib/rules/space-before-function-paren.js
index 51f6cc432..81697d64f 100644
--- a/lib/rules/space-before-function-paren.js
+++ b/lib/rules/space-before-function-paren.js
@@ -8,7 +8,7 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/space-in-parens.js b/lib/rules/space-in-parens.js
index 7e315c448..aa1374380 100644
--- a/lib/rules/space-in-parens.js
+++ b/lib/rules/space-in-parens.js
@@ -4,7 +4,7 @@
  */
 "use strict";
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/space-unary-ops.js b/lib/rules/space-unary-ops.js
index 6fbcc15c0..6fe25443c 100644
--- a/lib/rules/space-unary-ops.js
+++ b/lib/rules/space-unary-ops.js
@@ -8,7 +8,7 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/spaced-comment.js b/lib/rules/spaced-comment.js
index 3a76c0c26..6fbe2aac7 100644
--- a/lib/rules/spaced-comment.js
+++ b/lib/rules/spaced-comment.js
@@ -5,7 +5,7 @@
 "use strict";
 
 const lodash = require("lodash");
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Helpers
diff --git a/lib/rules/strict.js b/lib/rules/strict.js
index 633a8b323..8b5757738 100644
--- a/lib/rules/strict.js
+++ b/lib/rules/strict.js
@@ -9,7 +9,7 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Helpers
diff --git a/lib/rules/switch-colon-spacing.js b/lib/rules/switch-colon-spacing.js
index cf19df6ed..23dfff613 100644
--- a/lib/rules/switch-colon-spacing.js
+++ b/lib/rules/switch-colon-spacing.js
@@ -9,7 +9,7 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/symbol-description.js b/lib/rules/symbol-description.js
index 95c1a1deb..271012b54 100644
--- a/lib/rules/symbol-description.js
+++ b/lib/rules/symbol-description.js
@@ -9,7 +9,7 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/template-curly-spacing.js b/lib/rules/template-curly-spacing.js
index 707ea76a3..6702d730c 100644
--- a/lib/rules/template-curly-spacing.js
+++ b/lib/rules/template-curly-spacing.js
@@ -9,7 +9,7 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Helpers
diff --git a/lib/rules/wrap-iife.js b/lib/rules/wrap-iife.js
index a21bf2163..d006d30a0 100644
--- a/lib/rules/wrap-iife.js
+++ b/lib/rules/wrap-iife.js
@@ -9,7 +9,7 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Rule Definition
diff --git a/lib/rules/yoda.js b/lib/rules/yoda.js
index 7f3bc6115..35368dd4d 100644
--- a/lib/rules/yoda.js
+++ b/lib/rules/yoda.js
@@ -8,7 +8,7 @@
 // Requirements
 //--------------------------------------------------------------------------
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //--------------------------------------------------------------------------
 // Helpers
diff --git a/lib/token-store/index.js b/lib/token-store/index.js
index 1446b9ff0..d59a0bba0 100644
--- a/lib/token-store/index.js
+++ b/lib/token-store/index.js
@@ -13,7 +13,7 @@ const cursors = require("./cursors");
 const ForwardTokenCursor = require("./forward-token-cursor");
 const PaddedTokenCursor = require("./padded-token-cursor");
 const utils = require("./utils");
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Helpers
diff --git a/lib/ast-utils.js b/lib/util/ast-utils.js
similarity index 100%
rename from lib/ast-utils.js
rename to lib/util/ast-utils.js
diff --git a/lib/file-finder.js b/lib/util/file-finder.js
similarity index 100%
rename from lib/file-finder.js
rename to lib/util/file-finder.js
diff --git a/lib/util/fix-tracker.js b/lib/util/fix-tracker.js
index 067070df0..3c9bf63d2 100644
--- a/lib/util/fix-tracker.js
+++ b/lib/util/fix-tracker.js
@@ -8,7 +8,7 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const astUtils = require("../ast-utils");
+const astUtils = require("../util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Public Interface
diff --git a/lib/util/glob-util.js b/lib/util/glob-utils.js
similarity index 97%
rename from lib/util/glob-util.js
rename to lib/util/glob-utils.js
index 9d5d7e5aa..a2be0f042 100644
--- a/lib/util/glob-util.js
+++ b/lib/util/glob-utils.js
@@ -13,10 +13,10 @@ const lodash = require("lodash"),
     path = require("path"),
     GlobSync = require("./glob"),
 
-    pathUtil = require("./path-util"),
+    pathUtils = require("./path-utils"),
     IgnoredPaths = require("../ignored-paths");
 
-const debug = require("debug")("eslint:glob-util");
+const debug = require("debug")("eslint:glob-utils");
 
 //------------------------------------------------------------------------------
 // Helpers
@@ -77,7 +77,7 @@ function processPath(options) {
             newPath = pathname.replace(/[/\\]$/, "") + suffix;
         }
 
-        return pathUtil.convertPathToPosix(newPath);
+        return pathUtils.convertPathToPosix(newPath);
     };
 }
 
@@ -194,7 +194,7 @@ function listFilesToProcess(globPatterns, providedOptions) {
     );
 
     /*
-     * The test "should use default options if none are provided" (source-code-util.js) checks that 'module.exports.resolveFileGlobPatterns' was called.
+     * The test "should use default options if none are provided" (source-code-utils.js) checks that 'module.exports.resolveFileGlobPatterns' was called.
      * So it cannot use the local function "resolveFileGlobPatterns".
      */
     const resolvedGlobPatterns = module.exports.resolveFileGlobPatterns(globPatterns, options);
diff --git a/lib/util/naming.js b/lib/util/naming.js
index a5d6b9d79..aaf002378 100644
--- a/lib/util/naming.js
+++ b/lib/util/naming.js
@@ -7,7 +7,7 @@
 // Requirements
 //------------------------------------------------------------------------------
 
-const pathUtil = require("../util/path-util");
+const pathUtils = require("../util/path-utils");
 
 //------------------------------------------------------------------------------
 // Private
@@ -31,7 +31,7 @@ function normalizePackageName(name, prefix) {
      * https://github.com/eslint/eslint/issues/5644
      */
     if (normalizedName.indexOf("\\") > -1) {
-        normalizedName = pathUtil.convertPathToPosix(normalizedName);
+        normalizedName = pathUtils.convertPathToPosix(normalizedName);
     }
 
     if (normalizedName.charAt(0) === "@") {
diff --git a/lib/util/npm-util.js b/lib/util/npm-utils.js
similarity index 100%
rename from lib/util/npm-util.js
rename to lib/util/npm-utils.js
diff --git a/lib/util/path-util.js b/lib/util/path-utils.js
similarity index 96%
rename from lib/util/path-util.js
rename to lib/util/path-utils.js
index 54460ffd1..07cf4e790 100644
--- a/lib/util/path-util.js
+++ b/lib/util/path-utils.js
@@ -54,7 +54,7 @@ function getRelativePath(filepath, baseDir) {
 
     if (baseDir) {
         if (!path.isAbsolute(baseDir)) {
-            throw new Error("baseDir should be an absolute path");
+            throw new Error(`baseDir should be an absolute path: ${baseDir}`);
         }
         return path.relative(baseDir, absolutePath);
     }
diff --git a/lib/util/source-code-util.js b/lib/util/source-code-utils.js
similarity index 95%
rename from lib/util/source-code-util.js
rename to lib/util/source-code-utils.js
index 66d91cd21..cac13d370 100644
--- a/lib/util/source-code-util.js
+++ b/lib/util/source-code-utils.js
@@ -10,10 +10,10 @@
 //------------------------------------------------------------------------------
 
 const CLIEngine = require("../cli-engine"),
-    globUtil = require("./glob-util"),
+    globUtils = require("./glob-utils"),
     baseDefaultOptions = require("../../conf/default-cli-options");
 
-const debug = require("debug")("eslint:source-code-util");
+const debug = require("debug")("eslint:source-code-utils");
 
 //------------------------------------------------------------------------------
 // Helpers
@@ -79,7 +79,7 @@ function getSourceCodeOfFiles(patterns, providedOptions, providedCallback) {
     }
     debug("constructed options:", options);
 
-    const filenames = globUtil.listFilesToProcess(globPatternsList, options)
+    const filenames = globUtils.listFilesToProcess(globPatternsList, options)
         .filter(fileInfo => !fileInfo.ignored)
         .reduce((files, fileInfo) => files.concat(fileInfo.filename), []);
 
diff --git a/lib/util/source-code.js b/lib/util/source-code.js
index d34151995..dd45f6112 100644
--- a/lib/util/source-code.js
+++ b/lib/util/source-code.js
@@ -10,7 +10,7 @@
 
 const TokenStore = require("../token-store"),
     Traverser = require("./traverser"),
-    astUtils = require("../ast-utils"),
+    astUtils = require("../util/ast-utils"),
     lodash = require("lodash");
 
 //------------------------------------------------------------------------------
diff --git a/lib/util/unicode/index.js b/lib/util/unicode/index.js
new file mode 100644
index 000000000..02eea502d
--- /dev/null
+++ b/lib/util/unicode/index.js
@@ -0,0 +1,11 @@
+/**
+ * @author Toru Nagashima <https://github.com/mysticatea>
+ */
+"use strict";
+
+module.exports = {
+    isCombiningCharacter: require("./is-combining-character"),
+    isEmojiModifier: require("./is-emoji-modifier"),
+    isRegionalIndicatorSymbol: require("./is-regional-indicator-symbol"),
+    isSurrogatePair: require("./is-surrogate-pair")
+};
diff --git a/lib/util/unicode/is-combining-character.js b/lib/util/unicode/is-combining-character.js
new file mode 100644
index 000000000..0fa40ee4a
--- /dev/null
+++ b/lib/util/unicode/is-combining-character.js
@@ -0,0 +1,13 @@
+// THIS FILE WAS GENERATED BY 'tools/update-unicode-utils.js'
+"use strict";
+
+const combiningChars = new Set([768,769,770,771,772,773,774,775,776,777,778,779,780,781,782,783,784,785,786,787,788,789,790,791,792,793,794,795,796,797,798,799,800,801,802,803,804,805,806,807,808,809,810,811,812,813,814,815,816,817,818,819,820,821,822,823,824,825,826,827,828,829,830,831,832,833,834,835,836,837,838,839,840,841,842,843,844,845,846,847,848,849,850,851,852,853,854,855,856,857,858,859,860,861,862,863,864,865,866,867,868,869,870,871,872,873,874,875,876,877,878,879,1155,1156,1157,1158,1159,1160,1161,1425,1426,1427,1428,1429,1430,1431,1432,1433,1434,1435,1436,1437,1438,1439,1440,1441,1442,1443,1444,1445,1446,1447,1448,1449,1450,1451,1452,1453,1454,1455,1456,1457,1458,1459,1460,1461,1462,1463,1464,1465,1466,1467,1468,1469,1471,1473,1474,1476,1477,1479,1552,1553,1554,1555,1556,1557,1558,1559,1560,1561,1562,1611,1612,1613,1614,1615,1616,1617,1618,1619,1620,1621,1622,1623,1624,1625,1626,1627,1628,1629,1630,1631,1648,1750,1751,1752,1753,1754,1755,1756,1759,1760,1761,1762,1763,1764,1767,1768,1770,1771,1772,1773,1809,1840,1841,1842,1843,1844,1845,1846,1847,1848,1849,1850,1851,1852,1853,1854,1855,1856,1857,1858,1859,1860,1861,1862,1863,1864,1865,1866,1958,1959,1960,1961,1962,1963,1964,1965,1966,1967,1968,2027,2028,2029,2030,2031,2032,2033,2034,2035,2070,2071,2072,2073,2075,2076,2077,2078,2079,2080,2081,2082,2083,2085,2086,2087,2089,2090,2091,2092,2093,2137,2138,2139,2260,2261,2262,2263,2264,2265,2266,2267,2268,2269,2270,2271,2272,2273,2275,2276,2277,2278,2279,2280,2281,2282,2283,2284,2285,2286,2287,2288,2289,2290,2291,2292,2293,2294,2295,2296,2297,2298,2299,2300,2301,2302,2303,2304,2305,2306,2307,2362,2363,2364,2366,2367,2368,2369,2370,2371,2372,2373,2374,2375,2376,2377,2378,2379,2380,2381,2382,2383,2385,2386,2387,2388,2389,2390,2391,2402,2403,2433,2434,2435,2492,2494,2495,2496,2497,2498,2499,2500,2503,2504,2507,2508,2509,2519,2530,2531,2561,2562,2563,2620,2622,2623,2624,2625,2626,2631,2632,2635,2636,2637,2641,2672,2673,2677,2689,2690,2691,2748,2750,2751,2752,2753,2754,2755,2756,2757,2759,2760,2761,2763,2764,2765,2786,2787,2810,2811,2812,2813,2814,2815,2817,2818,2819,2876,2878,2879,2880,2881,2882,2883,2884,2887,2888,2891,2892,2893,2902,2903,2914,2915,2946,3006,3007,3008,3009,3010,3014,3015,3016,3018,3019,3020,3021,3031,3072,3073,3074,3075,3134,3135,3136,3137,3138,3139,3140,3142,3143,3144,3146,3147,3148,3149,3157,3158,3170,3171,3201,3202,3203,3260,3262,3263,3264,3265,3266,3267,3268,3270,3271,3272,3274,3275,3276,3277,3285,3286,3298,3299,3328,3329,3330,3331,3387,3388,3390,3391,3392,3393,3394,3395,3396,3398,3399,3400,3402,3403,3404,3405,3415,3426,3427,3458,3459,3530,3535,3536,3537,3538,3539,3540,3542,3544,3545,3546,3547,3548,3549,3550,3551,3570,3571,3633,3636,3637,3638,3639,3640,3641,3642,3655,3656,3657,3658,3659,3660,3661,3662,3761,3764,3765,3766,3767,3768,3769,3771,3772,3784,3785,3786,3787,3788,3789,3864,3865,3893,3895,3897,3902,3903,3953,3954,3955,3956,3957,3958,3959,3960,3961,3962,3963,3964,3965,3966,3967,3968,3969,3970,3971,3972,3974,3975,3981,3982,3983,3984,3985,3986,3987,3988,3989,3990,3991,3993,3994,3995,3996,3997,3998,3999,4000,4001,4002,4003,4004,4005,4006,4007,4008,4009,4010,4011,4012,4013,4014,4015,4016,4017,4018,4019,4020,4021,4022,4023,4024,4025,4026,4027,4028,4038,4139,4140,4141,4142,4143,4144,4145,4146,4147,4148,4149,4150,4151,4152,4153,4154,4155,4156,4157,4158,4182,4183,4184,4185,4190,4191,4192,4194,4195,4196,4199,4200,4201,4202,4203,4204,4205,4209,4210,4211,4212,4226,4227,4228,4229,4230,4231,4232,4233,4234,4235,4236,4237,4239,4250,4251,4252,4253,4957,4958,4959,5906,5907,5908,5938,5939,5940,5970,5971,6002,6003,6068,6069,6070,6071,6072,6073,6074,6075,6076,6077,6078,6079,6080,6081,6082,6083,6084,6085,6086,6087,6088,6089,6090,6091,6092,6093,6094,6095,6096,6097,6098,6099,6109,6155,6156,6157,6277,6278,6313,6432,6433,6434,6435,6436,6437,6438,6439,6440,6441,6442,6443,6448,6449,6450,6451,6452,6453,6454,6455,6456,6457,6458,6459,6679,6680,6681,6682,6683,6741,6742,6743,6744,6745,6746,6747,6748,6749,6750,6752,6753,6754,6755,6756,6757,6758,6759,6760,6761,6762,6763,6764,6765,6766,6767,6768,6769,6770,6771,6772,6773,6774,6775,6776,6777,6778,6779,6780,6783,6832,6833,6834,6835,6836,6837,6838,6839,6840,6841,6842,6843,6844,6845,6846,6912,6913,6914,6915,6916,6964,6965,6966,6967,6968,6969,6970,6971,6972,6973,6974,6975,6976,6977,6978,6979,6980,7019,7020,7021,7022,7023,7024,7025,7026,7027,7040,7041,7042,7073,7074,7075,7076,7077,7078,7079,7080,7081,7082,7083,7084,7085,7142,7143,7144,7145,7146,7147,7148,7149,7150,7151,7152,7153,7154,7155,7204,7205,7206,7207,7208,7209,7210,7211,7212,7213,7214,7215,7216,7217,7218,7219,7220,7221,7222,7223,7376,7377,7378,7380,7381,7382,7383,7384,7385,7386,7387,7388,7389,7390,7391,7392,7393,7394,7395,7396,7397,7398,7399,7400,7405,7410,7411,7412,7415,7416,7417,7616,7617,7618,7619,7620,7621,7622,7623,7624,7625,7626,7627,7628,7629,7630,7631,7632,7633,7634,7635,7636,7637,7638,7639,7640,7641,7642,7643,7644,7645,7646,7647,7648,7649,7650,7651,7652,7653,7654,7655,7656,7657,7658,7659,7660,7661,7662,7663,7664,7665,7666,7667,7668,7669,7670,7671,7672,7673,7675,7676,7677,7678,7679,8400,8401,8402,8403,8404,8405,8406,8407,8408,8409,8410,8411,8412,8413,8414,8415,8416,8417,8418,8419,8420,8421,8422,8423,8424,8425,8426,8427,8428,8429,8430,8431,8432,11503,11504,11505,11647,11744,11745,11746,11747,11748,11749,11750,11751,11752,11753,11754,11755,11756,11757,11758,11759,11760,11761,11762,11763,11764,11765,11766,11767,11768,11769,11770,11771,11772,11773,11774,11775,12330,12331,12332,12333,12334,12335,12441,12442,42607,42608,42609,42610,42612,42613,42614,42615,42616,42617,42618,42619,42620,42621,42654,42655,42736,42737,43010,43014,43019,43043,43044,43045,43046,43047,43136,43137,43188,43189,43190,43191,43192,43193,43194,43195,43196,43197,43198,43199,43200,43201,43202,43203,43204,43205,43232,43233,43234,43235,43236,43237,43238,43239,43240,43241,43242,43243,43244,43245,43246,43247,43248,43249,43302,43303,43304,43305,43306,43307,43308,43309,43335,43336,43337,43338,43339,43340,43341,43342,43343,43344,43345,43346,43347,43392,43393,43394,43395,43443,43444,43445,43446,43447,43448,43449,43450,43451,43452,43453,43454,43455,43456,43493,43561,43562,43563,43564,43565,43566,43567,43568,43569,43570,43571,43572,43573,43574,43587,43596,43597,43643,43644,43645,43696,43698,43699,43700,43703,43704,43710,43711,43713,43755,43756,43757,43758,43759,43765,43766,44003,44004,44005,44006,44007,44008,44009,44010,44012,44013,64286,65024,65025,65026,65027,65028,65029,65030,65031,65032,65033,65034,65035,65036,65037,65038,65039,65056,65057,65058,65059,65060,65061,65062,65063,65064,65065,65066,65067,65068,65069,65070,65071,66045,66272,66422,66423,66424,66425,66426,68097,68098,68099,68101,68102,68108,68109,68110,68111,68152,68153,68154,68159,68325,68326,69632,69633,69634,69688,69689,69690,69691,69692,69693,69694,69695,69696,69697,69698,69699,69700,69701,69702,69759,69760,69761,69762,69808,69809,69810,69811,69812,69813,69814,69815,69816,69817,69818,69888,69889,69890,69927,69928,69929,69930,69931,69932,69933,69934,69935,69936,69937,69938,69939,69940,70003,70016,70017,70018,70067,70068,70069,70070,70071,70072,70073,70074,70075,70076,70077,70078,70079,70080,70090,70091,70092,70188,70189,70190,70191,70192,70193,70194,70195,70196,70197,70198,70199,70206,70367,70368,70369,70370,70371,70372,70373,70374,70375,70376,70377,70378,70400,70401,70402,70403,70460,70462,70463,70464,70465,70466,70467,70468,70471,70472,70475,70476,70477,70487,70498,70499,70502,70503,70504,70505,70506,70507,70508,70512,70513,70514,70515,70516,70709,70710,70711,70712,70713,70714,70715,70716,70717,70718,70719,70720,70721,70722,70723,70724,70725,70726,70832,70833,70834,70835,70836,70837,70838,70839,70840,70841,70842,70843,70844,70845,70846,70847,70848,70849,70850,70851,71087,71088,71089,71090,71091,71092,71093,71096,71097,71098,71099,71100,71101,71102,71103,71104,71132,71133,71216,71217,71218,71219,71220,71221,71222,71223,71224,71225,71226,71227,71228,71229,71230,71231,71232,71339,71340,71341,71342,71343,71344,71345,71346,71347,71348,71349,71350,71351,71453,71454,71455,71456,71457,71458,71459,71460,71461,71462,71463,71464,71465,71466,71467,72193,72194,72195,72196,72197,72198,72199,72200,72201,72202,72243,72244,72245,72246,72247,72248,72249,72251,72252,72253,72254,72263,72273,72274,72275,72276,72277,72278,72279,72280,72281,72282,72283,72330,72331,72332,72333,72334,72335,72336,72337,72338,72339,72340,72341,72342,72343,72344,72345,72751,72752,72753,72754,72755,72756,72757,72758,72760,72761,72762,72763,72764,72765,72766,72767,72850,72851,72852,72853,72854,72855,72856,72857,72858,72859,72860,72861,72862,72863,72864,72865,72866,72867,72868,72869,72870,72871,72873,72874,72875,72876,72877,72878,72879,72880,72881,72882,72883,72884,72885,72886,73009,73010,73011,73012,73013,73014,73018,73020,73021,73023,73024,73025,73026,73027,73028,73029,73031,92912,92913,92914,92915,92916,92976,92977,92978,92979,92980,92981,92982,94033,94034,94035,94036,94037,94038,94039,94040,94041,94042,94043,94044,94045,94046,94047,94048,94049,94050,94051,94052,94053,94054,94055,94056,94057,94058,94059,94060,94061,94062,94063,94064,94065,94066,94067,94068,94069,94070,94071,94072,94073,94074,94075,94076,94077,94078,94095,94096,94097,94098,113821,113822,119141,119142,119143,119144,119145,119149,119150,119151,119152,119153,119154,119163,119164,119165,119166,119167,119168,119169,119170,119173,119174,119175,119176,119177,119178,119179,119210,119211,119212,119213,119362,119363,119364,121344,121345,121346,121347,121348,121349,121350,121351,121352,121353,121354,121355,121356,121357,121358,121359,121360,121361,121362,121363,121364,121365,121366,121367,121368,121369,121370,121371,121372,121373,121374,121375,121376,121377,121378,121379,121380,121381,121382,121383,121384,121385,121386,121387,121388,121389,121390,121391,121392,121393,121394,121395,121396,121397,121398,121403,121404,121405,121406,121407,121408,121409,121410,121411,121412,121413,121414,121415,121416,121417,121418,121419,121420,121421,121422,121423,121424,121425,121426,121427,121428,121429,121430,121431,121432,121433,121434,121435,121436,121437,121438,121439,121440,121441,121442,121443,121444,121445,121446,121447,121448,121449,121450,121451,121452,121461,121476,121499,121500,121501,121502,121503,121505,121506,121507,121508,121509,121510,121511,121512,121513,121514,121515,121516,121517,121518,121519,122880,122881,122882,122883,122884,122885,122886,122888,122889,122890,122891,122892,122893,122894,122895,122896,122897,122898,122899,122900,122901,122902,122903,122904,122907,122908,122909,122910,122911,122912,122913,122915,122916,122918,122919,122920,122921,122922,125136,125137,125138,125139,125140,125141,125142,125252,125253,125254,125255,125256,125257,125258,917760,917761,917762,917763,917764,917765,917766,917767,917768,917769,917770,917771,917772,917773,917774,917775,917776,917777,917778,917779,917780,917781,917782,917783,917784,917785,917786,917787,917788,917789,917790,917791,917792,917793,917794,917795,917796,917797,917798,917799,917800,917801,917802,917803,917804,917805,917806,917807,917808,917809,917810,917811,917812,917813,917814,917815,917816,917817,917818,917819,917820,917821,917822,917823,917824,917825,917826,917827,917828,917829,917830,917831,917832,917833,917834,917835,917836,917837,917838,917839,917840,917841,917842,917843,917844,917845,917846,917847,917848,917849,917850,917851,917852,917853,917854,917855,917856,917857,917858,917859,917860,917861,917862,917863,917864,917865,917866,917867,917868,917869,917870,917871,917872,917873,917874,917875,917876,917877,917878,917879,917880,917881,917882,917883,917884,917885,917886,917887,917888,917889,917890,917891,917892,917893,917894,917895,917896,917897,917898,917899,917900,917901,917902,917903,917904,917905,917906,917907,917908,917909,917910,917911,917912,917913,917914,917915,917916,917917,917918,917919,917920,917921,917922,917923,917924,917925,917926,917927,917928,917929,917930,917931,917932,917933,917934,917935,917936,917937,917938,917939,917940,917941,917942,917943,917944,917945,917946,917947,917948,917949,917950,917951,917952,917953,917954,917955,917956,917957,917958,917959,917960,917961,917962,917963,917964,917965,917966,917967,917968,917969,917970,917971,917972,917973,917974,917975,917976,917977,917978,917979,917980,917981,917982,917983,917984,917985,917986,917987,917988,917989,917990,917991,917992,917993,917994,917995,917996,917997,917998,917999])
+
+/**
+ * Check whether a given character is a combining mark or not.
+ * @param {number} c The character code to check.
+ * @returns {boolean} `true` if the character belongs to the category, one of `Mc`, `Me`, and `Mn`.
+ */
+module.exports = function isCombiningCharacter(c) {
+    return combiningChars.has(c);
+};
diff --git a/lib/util/unicode/is-emoji-modifier.js b/lib/util/unicode/is-emoji-modifier.js
new file mode 100644
index 000000000..1bd5f557d
--- /dev/null
+++ b/lib/util/unicode/is-emoji-modifier.js
@@ -0,0 +1,13 @@
+/**
+ * @author Toru Nagashima <https://github.com/mysticatea>
+ */
+"use strict";
+
+/**
+ * Check whether a given character is an emoji modifier.
+ * @param {number} code The character code to check.
+ * @returns {boolean} `true` if the character is an emoji modifier.
+ */
+module.exports = function isEmojiModifier(code) {
+    return code >= 0x1F3FB && code <= 0x1F3FF;
+};
diff --git a/lib/util/unicode/is-regional-indicator-symbol.js b/lib/util/unicode/is-regional-indicator-symbol.js
new file mode 100644
index 000000000..c48ed46ef
--- /dev/null
+++ b/lib/util/unicode/is-regional-indicator-symbol.js
@@ -0,0 +1,13 @@
+/**
+ * @author Toru Nagashima <https://github.com/mysticatea>
+ */
+"use strict";
+
+/**
+ * Check whether a given character is a regional indicator symbol.
+ * @param {number} code The character code to check.
+ * @returns {boolean} `true` if the character is a regional indicator symbol.
+ */
+module.exports = function isRegionalIndicatorSymbol(code) {
+    return code >= 0x1F1E6 && code <= 0x1F1FF;
+};
diff --git a/lib/util/unicode/is-surrogate-pair.js b/lib/util/unicode/is-surrogate-pair.js
new file mode 100644
index 000000000..b8e5c1cac
--- /dev/null
+++ b/lib/util/unicode/is-surrogate-pair.js
@@ -0,0 +1,14 @@
+/**
+ * @author Toru Nagashima <https://github.com/mysticatea>
+ */
+"use strict";
+
+/**
+ * Check whether given two characters are a surrogate pair.
+ * @param {number} lead The code of the lead character.
+ * @param {number} tail The code of the tail character.
+ * @returns {boolean} `true` if the character pair is a surrogate pair.
+ */
+module.exports = function isSurrogatePair(lead, tail) {
+    return lead >= 0xD800 && lead < 0xDC00 && tail >= 0xDC00 && tail < 0xE000;
+};
diff --git a/package.json b/package.json
index bc118bda6..d37b275f6 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "eslint",
-  "version": "5.2.0",
+  "version": "5.3.0",
   "author": "Nicholas C. Zakas <nicholas+npm@nczconsulting.com>",
   "description": "An AST-based pattern checker for JavaScript.",
   "bin": {
@@ -66,7 +66,7 @@
     "path-is-inside": "^1.0.2",
     "pluralize": "^7.0.0",
     "progress": "^2.0.0",
-    "regexpp": "^1.1.0",
+    "regexpp": "^2.0.0",
     "require-uncached": "^1.0.3",
     "semver": "^5.5.0",
     "string.prototype.matchall": "^2.0.0",
diff --git a/packages/eslint-config-eslint/default.yml b/packages/eslint-config-eslint/default.yml
index da4faf6e5..127e7d7d7 100644
--- a/packages/eslint-config-eslint/default.yml
+++ b/packages/eslint-config-eslint/default.yml
@@ -1,10 +1,6 @@
 extends:
     - "eslint:recommended"
     - "plugin:node/recommended"
-
-plugins:
-    - "node"
-
 rules:
     array-bracket-spacing: "error"
     array-callback-return: "error"
@@ -54,6 +50,7 @@ rules:
     new-parens: "error"
     no-alert: "error"
     no-array-constructor: "error"
+    no-async-promise-executor: "error"
     no-buffer-constructor: "error"
     no-caller: "error"
     no-catch-shadow: "error"
@@ -160,6 +157,7 @@ rules:
     quotes: ["error", "double"]
     quote-props: ["error", "as-needed"]
     radix: "error"
+    require-atomic-updates: "error"
     require-jsdoc: "error"
     rest-spread-spacing: "error"
     semi: "error"
diff --git a/tools/internal-rules/.eslintrc.yml b/tools/internal-rules/.eslintrc.yml
deleted file mode 100644
index 55398c72b..000000000
--- a/tools/internal-rules/.eslintrc.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-rules:
-    rulesdir/no-invalid-meta: "error"
-    rulesdir/consistent-docs-description: "error"
-    rulesdir/consistent-docs-url: "off"
diff --git a/tools/update-unicode-utils.js b/tools/update-unicode-utils.js
new file mode 100644
index 000000000..d2e7c0d78
--- /dev/null
+++ b/tools/update-unicode-utils.js
@@ -0,0 +1,47 @@
+/**
+ * @author Toru Nagashima <https://github.com/mysticatea>
+ */
+"use strict";
+
+const fs = require("fs");
+const path = require("path");
+
+/**
+ * Render the content of `lib/util/unicode/is-combining-character.js`.
+ * @param {number[]} chars The character code list to render.
+ * @returns {void}
+ */
+function renderIsCombiningCharacter(chars) {
+    return `// THIS FILE WAS GENERATED BY 'tools/update-unicode-utils.js'
+"use strict";
+
+const combiningChars = new Set(${JSON.stringify(chars)})
+
+/**
+ * Check whether a given character is a combining mark or not.
+ * @param {number} c The character code to check.
+ * @returns {boolean} \`true\` if the character belongs to the category, one of \`Mc\`, \`Me\`, and \`Mn\`.
+ */
+module.exports = function isCombiningCharacter(c) {
+    return combiningChars.has(c);
+};
+`;
+}
+
+//------------------------------------------------------------------------------
+// Main
+//------------------------------------------------------------------------------
+
+const combiningChars = Array.from(function *() {
+    for (let codePoint = 0; codePoint <= 0x10FFFF; ++codePoint) {
+        // eslint-disable-next-line node/no-unsupported-features/es-syntax
+        if (/^[\p{Mc}\p{Me}\p{Mn}]$/u.test(String.fromCodePoint(codePoint))) {
+            yield codePoint;
+        }
+    }
+}());
+
+fs.writeFileSync(
+    path.resolve(__dirname, "../lib/util/unicode/is-combining-character.js"),
+    renderIsCombiningCharacter(combiningChars)
+);


Test patch:
diff --git a/tests/fixtures/ignored-paths/crlf/.eslintignore b/tests/fixtures/ignored-paths/crlf/.eslintignore
new file mode 100644
index 000000000..a523bd68b
--- /dev/null
+++ b/tests/fixtures/ignored-paths/crlf/.eslintignore
@@ -0,0 +1,2 @@
+hide1/
+hide2/
diff --git a/tests/fixtures/ignored-paths/subdir/.eslintignoreInChildDir b/tests/fixtures/ignored-paths/subdir/.eslintignoreInChildDir
new file mode 100644
index 000000000..8c7a20132
--- /dev/null
+++ b/tests/fixtures/ignored-paths/subdir/.eslintignoreInChildDir
@@ -0,0 +1,5 @@
+/undef.js
+foo.js
+*.txt
+!/bar.txt
+!baz.txt
diff --git a/tests/lib/cli-engine.js b/tests/lib/cli-engine.js
index 7643a241d..cac7671b1 100644
--- a/tests/lib/cli-engine.js
+++ b/tests/lib/cli-engine.js
@@ -1473,6 +1473,31 @@ describe("CLIEngine", () => {
                 });
             });
 
+            it("should run autofix even if files are cached without autofix results", () => {
+                const baseOptions = {
+                    cwd: path.join(fixtureDir, ".."),
+                    useEslintrc: false,
+                    rules: {
+                        semi: 2,
+                        quotes: [2, "double"],
+                        eqeqeq: 2,
+                        "no-undef": 2,
+                        "space-infix-ops": 2
+                    }
+                };
+
+                engine = new CLIEngine(Object.assign({}, baseOptions, { cache: true, fix: false }));
+
+                // Do initial lint run and populate the cache file
+                engine.executeOnFiles([path.resolve(fixtureDir, `${fixtureDir}/fixmode`)]);
+
+                engine = new CLIEngine(Object.assign({}, baseOptions, { cache: true, fix: true }));
+
+                const report = engine.executeOnFiles([path.resolve(fixtureDir, `${fixtureDir}/fixmode`)]);
+
+                assert.ok(report.results.some(result => result.output));
+            });
+
         });
 
         // These tests have to do with https://github.com/eslint/eslint/issues/963
diff --git a/tests/lib/config/autoconfig.js b/tests/lib/config/autoconfig.js
index fb8e12e94..7d304eeb4 100644
--- a/tests/lib/config/autoconfig.js
+++ b/tests/lib/config/autoconfig.js
@@ -11,7 +11,7 @@
 
 const assert = require("chai").assert,
     autoconfig = require("../../../lib/config/autoconfig"),
-    sourceCodeUtil = require("../../../lib/util/source-code-util"),
+    sourceCodeUtils = require("../../../lib/util/source-code-utils"),
     baseDefaultOptions = require("../../../conf/default-cli-options");
 
 const defaultOptions = Object.assign({}, baseDefaultOptions, { cwd: process.cwd() });
@@ -174,7 +174,7 @@ describe("autoconfig", () => {
 
             beforeEach(() => {
                 const config = { ignore: false };
-                const sourceCode = sourceCodeUtil.getSourceCodeOfFiles(SOURCE_CODE_FIXTURE_FILENAME, config);
+                const sourceCode = sourceCodeUtils.getSourceCodeOfFiles(SOURCE_CODE_FIXTURE_FILENAME, config);
 
                 registry = new autoconfig.Registry(rulesConfig);
                 registry = registry.lintSourceCode(sourceCode, defaultOptions);
@@ -201,7 +201,7 @@ describe("autoconfig", () => {
 
             it("should respect inline eslint config comments (and not crash when they make linting errors)", () => {
                 const config = { ignore: false };
-                const sourceCode = sourceCodeUtil.getSourceCodeOfFiles(CONFIG_COMMENTS_FILENAME, config);
+                const sourceCode = sourceCodeUtils.getSourceCodeOfFiles(CONFIG_COMMENTS_FILENAME, config);
                 const expectedRegistry = [
                     { config: 2, specificity: 1, errorCount: 3 },
                     { config: [2, "always"], specificity: 2, errorCount: 3 },
@@ -220,7 +220,7 @@ describe("autoconfig", () => {
 
             beforeEach(() => {
                 const config = { ignore: false };
-                const sourceCode = sourceCodeUtil.getSourceCodeOfFiles(SOURCE_CODE_FIXTURE_FILENAME, config);
+                const sourceCode = sourceCodeUtils.getSourceCodeOfFiles(SOURCE_CODE_FIXTURE_FILENAME, config);
 
                 registry = new autoconfig.Registry(rulesConfig);
                 registry = registry.lintSourceCode(sourceCode, defaultOptions);
@@ -248,7 +248,7 @@ describe("autoconfig", () => {
 
             beforeEach(() => {
                 const config = { ignore: false };
-                const sourceCode = sourceCodeUtil.getSourceCodeOfFiles(SOURCE_CODE_FIXTURE_FILENAME, config);
+                const sourceCode = sourceCodeUtils.getSourceCodeOfFiles(SOURCE_CODE_FIXTURE_FILENAME, config);
                 let registry = new autoconfig.Registry(errorRulesConfig);
 
                 registry = registry.lintSourceCode(sourceCode, defaultOptions);
@@ -269,7 +269,7 @@ describe("autoconfig", () => {
 
             beforeEach(() => {
                 const config = { ignore: false };
-                const sourceCode = sourceCodeUtil.getSourceCodeOfFiles(SOURCE_CODE_FIXTURE_FILENAME, config);
+                const sourceCode = sourceCodeUtils.getSourceCodeOfFiles(SOURCE_CODE_FIXTURE_FILENAME, config);
                 let registry = new autoconfig.Registry(rulesConfig);
 
                 registry = registry.lintSourceCode(sourceCode, defaultOptions);
@@ -293,7 +293,7 @@ describe("autoconfig", () => {
 
             it("should not care how many errors the config has", () => {
                 const config = { ignore: false };
-                const sourceCode = sourceCodeUtil.getSourceCodeOfFiles(SOURCE_CODE_FIXTURE_FILENAME, config);
+                const sourceCode = sourceCodeUtils.getSourceCodeOfFiles(SOURCE_CODE_FIXTURE_FILENAME, config);
                 let registry = new autoconfig.Registry(errorRulesConfig);
 
                 registry = registry.lintSourceCode(sourceCode, defaultOptions);
diff --git a/tests/lib/config/config-initializer.js b/tests/lib/config/config-initializer.js
index 91cc6476b..3767fe376 100644
--- a/tests/lib/config/config-initializer.js
+++ b/tests/lib/config/config-initializer.js
@@ -16,7 +16,7 @@ const assert = require("chai").assert,
     sinon = require("sinon"),
     sh = require("shelljs"),
     autoconfig = require("../../../lib/config/autoconfig"),
-    npmUtil = require("../../../lib/util/npm-util");
+    npmUtils = require("../../../lib/util/npm-utils");
 
 const originalDir = process.cwd();
 const proxyquire = require("proxyquire").noPreserveCache();
@@ -83,13 +83,13 @@ describe("configInitializer", () => {
     });
 
     beforeEach(() => {
-        npmInstallStub = sinon.stub(npmUtil, "installSyncSaveDev");
-        npmCheckStub = sinon.stub(npmUtil, "checkDevDeps").callsFake(packages => packages.reduce((status, pkg) => {
+        npmInstallStub = sinon.stub(npmUtils, "installSyncSaveDev");
+        npmCheckStub = sinon.stub(npmUtils, "checkDevDeps").callsFake(packages => packages.reduce((status, pkg) => {
             status[pkg] = false;
             return status;
         }, {}));
         npmFetchPeerDependenciesStub = sinon
-            .stub(npmUtil, "fetchPeerDependencies")
+            .stub(npmUtils, "fetchPeerDependencies")
             .returns({
                 eslint: "^3.19.0",
                 "eslint-plugin-jsx-a11y": "^5.0.1",
diff --git a/tests/lib/ignored-paths.js b/tests/lib/ignored-paths.js
index 010488931..b03314e61 100644
--- a/tests/lib/ignored-paths.js
+++ b/tests/lib/ignored-paths.js
@@ -123,7 +123,7 @@ describe("IgnoredPaths", () => {
             const ignoredPaths = new IgnoredPaths({ ignore: true, cwd: getFixturePath() });
             const ignorePatterns = getIgnorePatterns(ignoredPaths);
 
-            assert.isNotNull(ignoredPaths.baseDir);
+            assert.isNotNull(ignoredPaths.ignoreFileDir);
             assert.deepStrictEqual(getIgnoreFiles(ignoredPaths), [expectedIgnoreFile]);
             assert.include(ignorePatterns, "sampleignorepattern");
         });
@@ -131,7 +131,7 @@ describe("IgnoredPaths", () => {
         it("should set baseDir to cwd when no ignore file was loaded", () => {
             const ignoredPaths = new IgnoredPaths({ cwd: getFixturePath("no-ignore-file") });
 
-            assert.strictEqual(ignoredPaths.baseDir, getFixturePath("no-ignore-file"));
+            assert.strictEqual(ignoredPaths.ignoreFileDir, getFixturePath("no-ignore-file"));
         });
 
         it("should not travel to parent directories to find .eslintignore when it's missing and cwd is provided", () => {
@@ -241,7 +241,21 @@ describe("IgnoredPaths", () => {
         it("should set baseDir to directory containing ignorePath if provided", () => {
             const ignoredPaths = new IgnoredPaths({ ignore: true, ignorePath: ignoreFilePath, cwd: getFixturePath() });
 
-            assert.strictEqual(ignoredPaths.baseDir, path.dirname(ignoreFilePath));
+            assert.strictEqual(ignoredPaths.ignoreFileDir, path.dirname(ignoreFilePath));
+        });
+
+        it("should set the common ancestor directory of cwd and ignorePath to baseDir (in the case that 'ignoreFilePath' and 'cwd' are siblings)", () => {
+            const baseDir = path.dirname(ignoreFilePath);
+            const ignoredPaths = new IgnoredPaths({ ignore: true, ignorePath: ignoreFilePath, cwd: path.resolve(baseDir, "testcwd") });
+
+            assert.strictEqual(ignoredPaths.getBaseDir(), baseDir);
+        });
+
+        it("should set the common ancestor directory of cwd and ignorePath to baseDir", () => {
+            const baseDir = path.resolve(ignoreFilePath, "../../..");
+            const ignoredPaths = new IgnoredPaths({ ignore: true, ignorePath: ignoreFilePath, cwd: path.resolve(baseDir, "fix/testcwd") });
+
+            assert.strictEqual(ignoredPaths.getBaseDir(), baseDir);
         });
 
     });
@@ -401,6 +415,56 @@ describe("IgnoredPaths", () => {
             assert.isFalse(ignoredPaths.contains(getFixturePath("subdir/undef.js")));
             assert.isTrue(ignoredPaths.contains(getFixturePath("undef.js")));
         });
+
+        it("should resolve relative paths from the ignorePath when it's in a child directory", () => {
+            const ignoredPaths = new IgnoredPaths({ ignore: true, ignorePath: getFixturePath("subdir/.eslintignoreInChildDir"), cwd: getFixturePath() });
+
+            assert.isTrue(ignoredPaths.contains(getFixturePath("subdir/undef.js")));
+            assert.isFalse(ignoredPaths.contains(getFixturePath("undef.js")));
+            assert.isTrue(ignoredPaths.contains(getFixturePath("foo.js")));
+            assert.isTrue(ignoredPaths.contains(getFixturePath("subdir/foo.js")));
+
+            assert.isTrue(ignoredPaths.contains(getFixturePath("node_modules/bar.js")));
+        });
+
+        it("should resolve relative paths from the ignorePath when it contains negated globs", () => {
+            const ignoredPaths = new IgnoredPaths({ ignore: true, ignorePath: getFixturePath("subdir/.eslintignoreInChildDir"), cwd: getFixturePath() });
+
+            assert.isTrue(ignoredPaths.contains("subdir/blah.txt"));
+            assert.isTrue(ignoredPaths.contains("blah.txt"));
+            assert.isFalse(ignoredPaths.contains("subdir/bar.txt"));
+            assert.isTrue(ignoredPaths.contains("bar.txt"));
+            assert.isFalse(ignoredPaths.contains("subdir/baz.txt"));
+            assert.isFalse(ignoredPaths.contains("baz.txt"));
+        });
+
+        it("should resolve default ignore patterns from the CWD even when the ignorePath is in a subdirectory", () => {
+            const ignoredPaths = new IgnoredPaths({ ignore: true, ignorePath: getFixturePath("subdir/.eslintignoreInChildDir"), cwd: getFixturePath() });
+
+            assert.isTrue(ignoredPaths.contains("node_modules/blah.js"));
+        });
+
+        it("should resolve default ignore patterns from the CWD even when the ignorePath is in a parent directory", () => {
+            const ignoredPaths = new IgnoredPaths({ ignore: true, ignorePath: getFixturePath(".eslintignoreForDifferentCwd"), cwd: getFixturePath("subdir") });
+
+            assert.isTrue(ignoredPaths.contains("node_modules/blah.js"));
+        });
+
+        it("should handle .eslintignore which contains CRLF correctly.", () => {
+            const ignoreFileContent = fs.readFileSync(getFixturePath("crlf/.eslintignore"), "utf8");
+
+            assert.isTrue(ignoreFileContent.includes("\r"), "crlf/.eslintignore should contains CR.");
+
+            const ignoredPaths = new IgnoredPaths({
+                ignore: true,
+                ignorePath: getFixturePath("crlf/.eslintignore"),
+                cwd: getFixturePath()
+            });
+
+            assert.isTrue(ignoredPaths.contains(getFixturePath("crlf/hide1/a.js")));
+            assert.isTrue(ignoredPaths.contains(getFixturePath("crlf/hide2/a.js")));
+            assert.isFalse(ignoredPaths.contains(getFixturePath("crlf/hide3/a.js")));
+        });
     });
 
     describe("initialization with ignorePath containing commented lines", () => {
@@ -610,6 +674,12 @@ describe("IgnoredPaths", () => {
             assert.isTrue(shouldIgnore(resolve("bower_components/a/b")));
             assert.isFalse(shouldIgnore(resolve(".hidden")));
             assert.isTrue(shouldIgnore(resolve(".hidden/a")));
+
+            assert.isFalse(shouldIgnore(resolve("..")));
+            assert.isFalse(shouldIgnore(resolve("../..")));
+            assert.isFalse(shouldIgnore(resolve("../foo")));
+            assert.isFalse(shouldIgnore(resolve("../../..")));
+            assert.isFalse(shouldIgnore(resolve("../../foo")));
         });
 
         it("should ignore default folders when there is an ignore file without unignored defaults", () => {
diff --git a/tests/lib/rules/indent.js b/tests/lib/rules/indent.js
index ab8ba4c18..b25e25949 100644
--- a/tests/lib/rules/indent.js
+++ b/tests/lib/rules/indent.js
@@ -64,7 +64,7 @@ function unIndent(strings) {
     const templateValue = strings[0];
     const lines = templateValue.replace(/^\n/, "").replace(/\n\s*$/, "").split("\n");
     const lineIndents = lines.filter(line => line.trim()).map(line => line.match(/ */)[0].length);
-    const minLineIndent = Math.min.apply(null, lineIndents);
+    const minLineIndent = Math.min(...lineIndents);
 
     return lines.map(line => line.slice(minLineIndent)).join("\n");
 }
@@ -4843,6 +4843,56 @@ ruleTester.run("indent", rule, {
                         2
                 }
             }
+        `,
+
+        //----------------------------------------------------------------------
+        // Comment alignment tests
+        //----------------------------------------------------------------------
+        unIndent`
+            if (foo) {
+            // Comment can align with code immediately above even if "incorrect" alignment
+                doSomething();
+            }
+        `,
+        unIndent`
+            if (foo) {
+                doSomething();
+            // Comment can align with code immediately below even if "incorrect" alignment
+            }
+        `,
+        unIndent`
+            if (foo) {
+                // Comment can be in correct alignment even if not aligned with code above/below
+            }
+        `,
+        unIndent`
+            if (foo) {
+
+                // Comment can be in correct alignment even if gaps between (and not aligned with) code above/below
+
+            }
+        `,
+        unIndent`
+            [{
+                foo
+            },
+
+            // Comment between nodes
+
+            {
+                bar
+            }];
+        `,
+        unIndent`
+            [{
+                foo
+            },
+
+            // Comment between nodes
+
+            { // comment
+                bar
+            }];
         `
     ],
 
@@ -9383,6 +9433,71 @@ ruleTester.run("indent", rule, {
                 }
             `,
             errors: expectedErrors([4, 12, 8, "Numeric"])
+        },
+
+        //----------------------------------------------------------------------
+        // Comment alignment tests
+        //----------------------------------------------------------------------
+        {
+            code: unIndent`
+                if (foo) {
+
+                // Comment cannot align with code immediately above if there is a whitespace gap
+                    doSomething();
+                }
+            `,
+            output: unIndent`
+                if (foo) {
+
+                    // Comment cannot align with code immediately above if there is a whitespace gap
+                    doSomething();
+                }
+            `,
+            errors: expectedErrors([3, 4, 0, "Line"])
+        },
+        {
+            code: unIndent`
+                if (foo) {
+                    foo(
+                        bar);
+                // Comment cannot align with code immediately below if there is a whitespace gap
+
+                }
+            `,
+            output: unIndent`
+                if (foo) {
+                    foo(
+                        bar);
+                    // Comment cannot align with code immediately below if there is a whitespace gap
+
+                }
+            `,
+            errors: expectedErrors([4, 4, 0, "Line"])
+        },
+        {
+            code: unIndent`
+                [{
+                    foo
+                },
+
+                    // Comment between nodes
+
+                {
+                    bar
+                }];
+            `,
+            output: unIndent`
+                [{
+                    foo
+                },
+
+                // Comment between nodes
+
+                {
+                    bar
+                }];
+            `,
+            errors: expectedErrors([5, 0, 4, "Line"])
         }
     ]
 });
diff --git a/tests/lib/rules/line-comment-position.js b/tests/lib/rules/line-comment-position.js
index fcc70c9fa..546ca1581 100644
--- a/tests/lib/rules/line-comment-position.js
+++ b/tests/lib/rules/line-comment-position.js
@@ -76,6 +76,10 @@ ruleTester.run("line-comment-position", rule, {
         {
             code: "// pragma valid comment\n1 + 1;",
             options: [{ position: "beside", ignorePattern: "pragma|linter" }]
+        },
+        {
+            code: "// above\n1 + 1; // ignored",
+            options: [{ ignorePattern: "ignored" }]
         }
     ],
 
diff --git a/tests/lib/rules/no-async-promise-executor.js b/tests/lib/rules/no-async-promise-executor.js
new file mode 100644
index 000000000..d5bcd0ae9
--- /dev/null
+++ b/tests/lib/rules/no-async-promise-executor.js
@@ -0,0 +1,61 @@
+/**
+ * @fileoverview disallow using an async function as a Promise executor
+ * @author Teddy Katz
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Requirements
+//------------------------------------------------------------------------------
+
+const rule = require("../../../lib/rules/no-async-promise-executor");
+const RuleTester = require("../../../lib/testers/rule-tester");
+
+
+//------------------------------------------------------------------------------
+// Tests
+//------------------------------------------------------------------------------
+
+const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 8 } });
+
+ruleTester.run("no-async-promise-executor", rule, {
+
+    valid: [
+        "new Promise((resolve, reject) => {})",
+        "new Promise((resolve, reject) => {}, async function unrelated() {})",
+        "new Foo(async (resolve, reject) => {})"
+    ],
+
+    invalid: [
+        {
+            code: "new Promise(async function foo(resolve, reject) {})",
+            errors: [{
+                message: "Promise executor functions should not be async.",
+                line: 1,
+                column: 13,
+                endLine: 1,
+                endColumn: 18
+            }]
+        },
+        {
+            code: "new Promise(async (resolve, reject) => {})",
+            errors: [{
+                message: "Promise executor functions should not be async.",
+                line: 1,
+                column: 13,
+                endLine: 1,
+                endColumn: 18
+            }]
+        },
+        {
+            code: "new Promise(((((async () => {})))))",
+            errors: [{
+                message: "Promise executor functions should not be async.",
+                line: 1,
+                column: 17,
+                endLine: 1,
+                endColumn: 22
+            }]
+        }
+    ]
+});
diff --git a/tests/lib/rules/no-misleading-character-class.js b/tests/lib/rules/no-misleading-character-class.js
new file mode 100644
index 000000000..98201186d
--- /dev/null
+++ b/tests/lib/rules/no-misleading-character-class.js
@@ -0,0 +1,272 @@
+/**
+ * @author Toru Nagashima <https://github.com/mysticatea>
+ */
+
+"use strict";
+
+//------------------------------------------------------------------------------
+// Requirements
+//------------------------------------------------------------------------------
+
+const rule = require("../../../lib/rules/no-misleading-character-class"),
+    RuleTester = require("../../../lib/testers/rule-tester");
+
+//------------------------------------------------------------------------------
+// Helpers
+//------------------------------------------------------------------------------
+
+const ruleTester = new RuleTester({
+    parserOptions: { ecmaVersion: 2015 }
+});
+
+/*
+ * /[👍]/ // ERROR: a surrogate pair in a character class without u flag.
+ * /[❇️]/u // ERROR: variation selectors in a character class.
+ * /[👨‍👩‍👦]/u // ERROR: ZWJ in a character class.
+ * /[🇯🇵]/u // ERROR: a U+1F1E6-1F1FF pair in a character class.
+ * /[👶🏻]/u // ERROR: an emoji which is made with an emoji and skin tone selector, in a character class.
+ */
+
+ruleTester.run("no-misleading-character-class", rule, {
+    valid: [
+        "var r = /[👍]/u",
+        "var r = /[\\uD83D\\uDC4D]/u",
+        "var r = /[\\u{1F44D}]/u",
+        "var r = /❇️/",
+        "var r = /Á/",
+        "var r = /[❇]/",
+        "var r = /👶🏻/",
+        "var r = /[👶]/u",
+        "var r = /🇯🇵/",
+        "var r = /[JP]/",
+        "var r = /👨‍👩‍👦/",
+
+        // Ignore solo lead/tail surrogate.
+        "var r = /[\\uD83D]/",
+        "var r = /[\\uDC4D]/",
+        "var r = /[\\uD83D]/u",
+        "var r = /[\\uDC4D]/u",
+
+        // Ignore solo combining char.
+        "var r = /[\\u0301]/",
+        "var r = /[\\uFE0F]/",
+        "var r = /[\\u0301]/u",
+        "var r = /[\\uFE0F]/u",
+
+        // Ignore solo emoji modifier.
+        "var r = /[\\u{1F3FB}]/u",
+        "var r = /[\u{1F3FB}]/u",
+
+        // Ignore solo regional indicator symbol.
+        "var r = /[🇯]/u",
+        "var r = /[🇵]/u",
+
+        // Ignore solo ZWJ.
+        "var r = /[\\u200D]/",
+        "var r = /[\\u200D]/u"
+    ],
+    invalid: [
+
+        // RegExp Literals.
+        {
+            code: "var r = /[👍]/",
+            errors: [{ messageId: "surrogatePairWithoutUFlag" }]
+        },
+        {
+            code: "var r = /[\\uD83D\\uDC4D]/",
+            errors: [{ messageId: "surrogatePairWithoutUFlag" }]
+        },
+        {
+            code: "var r = /[Á]/",
+            errors: [{ messageId: "combiningClass" }]
+        },
+        {
+            code: "var r = /[Á]/u",
+            errors: [{ messageId: "combiningClass" }]
+        },
+        {
+            code: "var r = /[\\u0041\\u0301]/",
+            errors: [{ messageId: "combiningClass" }]
+        },
+        {
+            code: "var r = /[\\u0041\\u0301]/u",
+            errors: [{ messageId: "combiningClass" }]
+        },
+        {
+            code: "var r = /[\\u{41}\\u{301}]/u",
+            errors: [{ messageId: "combiningClass" }]
+        },
+        {
+            code: "var r = /[❇️]/",
+            errors: [{ messageId: "combiningClass" }]
+        },
+        {
+            code: "var r = /[❇️]/u",
+            errors: [{ messageId: "combiningClass" }]
+        },
+        {
+            code: "var r = /[\\u2747\\uFE0F]/",
+            errors: [{ messageId: "combiningClass" }]
+        },
+        {
+            code: "var r = /[\\u2747\\uFE0F]/u",
+            errors: [{ messageId: "combiningClass" }]
+        },
+        {
+            code: "var r = /[\\u{2747}\\u{FE0F}]/u",
+            errors: [{ messageId: "combiningClass" }]
+        },
+        {
+            code: "var r = /[👶🏻]/",
+            errors: [{ messageId: "surrogatePairWithoutUFlag" }]
+        },
+        {
+            code: "var r = /[👶🏻]/u",
+            errors: [{ messageId: "emojiModifier" }]
+        },
+        {
+            code: "var r = /[\\uD83D\\uDC76\\uD83C\\uDFFB]/u",
+            errors: [{ messageId: "emojiModifier" }]
+        },
+        {
+            code: "var r = /[\\u{1F476}\\u{1F3FB}]/u",
+            errors: [{ messageId: "emojiModifier" }]
+        },
+        {
+            code: "var r = /[🇯🇵]/",
+            errors: [{ messageId: "surrogatePairWithoutUFlag" }]
+        },
+        {
+            code: "var r = /[🇯🇵]/u",
+            errors: [{ messageId: "regionalIndicatorSymbol" }]
+        },
+        {
+            code: "var r = /[\\uD83C\\uDDEF\\uD83C\\uDDF5]/u",
+            errors: [{ messageId: "regionalIndicatorSymbol" }]
+        },
+        {
+            code: "var r = /[\\u{1F1EF}\\u{1F1F5}]/u",
+            errors: [{ messageId: "regionalIndicatorSymbol" }]
+        },
+        {
+            code: "var r = /[👨‍👩‍👦]/",
+            errors: [
+                { messageId: "surrogatePairWithoutUFlag" },
+                { messageId: "zwj" }
+            ]
+        },
+        {
+            code: "var r = /[👨‍👩‍👦]/u",
+            errors: [{ messageId: "zwj" }]
+        },
+        {
+            code: "var r = /[\\uD83D\\uDC68\\u200D\\uD83D\\uDC69\\u200D\\uD83D\\uDC66]/u",
+            errors: [{ messageId: "zwj" }]
+        },
+        {
+            code: "var r = /[\\u{1F468}\\u{200D}\\u{1F469}\\u{200D}\\u{1F466}]/u",
+            errors: [{ messageId: "zwj" }]
+        },
+
+        // RegExp constructors.
+        {
+            code: String.raw`var r = new RegExp("[👍]", "")`,
+            errors: [{ messageId: "surrogatePairWithoutUFlag" }]
+        },
+        {
+            code: String.raw`var r = new RegExp("[\\uD83D\\uDC4D]", "")`,
+            errors: [{ messageId: "surrogatePairWithoutUFlag" }]
+        },
+        {
+            code: String.raw`var r = new RegExp("[Á]", "")`,
+            errors: [{ messageId: "combiningClass" }]
+        },
+        {
+            code: String.raw`var r = new RegExp("[Á]", "u")`,
+            errors: [{ messageId: "combiningClass" }]
+        },
+        {
+            code: String.raw`var r = new RegExp("[\\u0041\\u0301]", "")`,
+            errors: [{ messageId: "combiningClass" }]
+        },
+        {
+            code: String.raw`var r = new RegExp("[\\u0041\\u0301]", "u")`,
+            errors: [{ messageId: "combiningClass" }]
+        },
+        {
+            code: String.raw`var r = new RegExp("[\\u{41}\\u{301}]", "u")`,
+            errors: [{ messageId: "combiningClass" }]
+        },
+        {
+            code: String.raw`var r = new RegExp("[❇️]", "")`,
+            errors: [{ messageId: "combiningClass" }]
+        },
+        {
+            code: String.raw`var r = new RegExp("[❇️]", "u")`,
+            errors: [{ messageId: "combiningClass" }]
+        },
+        {
+            code: String.raw`var r = new RegExp("[\\u2747\\uFE0F]", "")`,
+            errors: [{ messageId: "combiningClass" }]
+        },
+        {
+            code: String.raw`var r = new RegExp("[\\u2747\\uFE0F]", "u")`,
+            errors: [{ messageId: "combiningClass" }]
+        },
+        {
+            code: String.raw`var r = new RegExp("[\\u{2747}\\u{FE0F}]", "u")`,
+            errors: [{ messageId: "combiningClass" }]
+        },
+        {
+            code: String.raw`var r = new RegExp("[👶🏻]", "")`,
+            errors: [{ messageId: "surrogatePairWithoutUFlag" }]
+        },
+        {
+            code: String.raw`var r = new RegExp("[👶🏻]", "u")`,
+            errors: [{ messageId: "emojiModifier" }]
+        },
+        {
+            code: String.raw`var r = new RegExp("[\\uD83D\\uDC76\\uD83C\\uDFFB]", "u")`,
+            errors: [{ messageId: "emojiModifier" }]
+        },
+        {
+            code: String.raw`var r = new RegExp("[\\u{1F476}\\u{1F3FB}]", "u")`,
+            errors: [{ messageId: "emojiModifier" }]
+        },
+        {
+            code: String.raw`var r = new RegExp("[🇯🇵]", "")`,
+            errors: [{ messageId: "surrogatePairWithoutUFlag" }]
+        },
+        {
+            code: String.raw`var r = new RegExp("[🇯🇵]", "u")`,
+            errors: [{ messageId: "regionalIndicatorSymbol" }]
+        },
+        {
+            code: String.raw`var r = new RegExp("[\\uD83C\\uDDEF\\uD83C\\uDDF5]", "u")`,
+            errors: [{ messageId: "regionalIndicatorSymbol" }]
+        },
+        {
+            code: String.raw`var r = new RegExp("[\\u{1F1EF}\\u{1F1F5}]", "u")`,
+            errors: [{ messageId: "regionalIndicatorSymbol" }]
+        },
+        {
+            code: String.raw`var r = new RegExp("[👨‍👩‍👦]", "")`,
+            errors: [
+                { messageId: "surrogatePairWithoutUFlag" },
+                { messageId: "zwj" }
+            ]
+        },
+        {
+            code: String.raw`var r = new RegExp("[👨‍👩‍👦]", "u")`,
+            errors: [{ messageId: "zwj" }]
+        },
+        {
+            code: String.raw`var r = new RegExp("[\\uD83D\\uDC68\\u200D\\uD83D\\uDC69\\u200D\\uD83D\\uDC66]", "u")`,
+            errors: [{ messageId: "zwj" }]
+        },
+        {
+            code: String.raw`var r = new RegExp("[\\u{1F468}\\u{200D}\\u{1F469}\\u{200D}\\u{1F466}]", "u")`,
+            errors: [{ messageId: "zwj" }]
+        }
+    ]
+});
diff --git a/tests/lib/rules/padding-line-between-statements.js b/tests/lib/rules/padding-line-between-statements.js
index 597c48835..3f72f8ff2 100644
--- a/tests/lib/rules/padding-line-between-statements.js
+++ b/tests/lib/rules/padding-line-between-statements.js
@@ -19,7 +19,7 @@ const RuleTester = require("../../../lib/testers/rule-tester");
 const MESSAGE_NEVER = "Unexpected blank line before this statement.";
 const MESSAGE_ALWAYS = "Expected blank line before this statement.";
 
-const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 2015 } });
+const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 2017 } });
 
 ruleTester.run("padding-line-between-statements", rule, {
     valid: [
@@ -811,6 +811,13 @@ ruleTester.run("padding-line-between-statements", rule, {
                 { blankLine: "always", prev: "function", next: "*" }
             ]
         },
+        {
+            code: "async function foo(){}\n\nfoo()",
+            options: [
+                { blankLine: "never", prev: "*", next: "*" },
+                { blankLine: "always", prev: "function", next: "*" }
+            ]
+        },
 
         //----------------------------------------------------------------------
         // if
@@ -3317,6 +3324,15 @@ ruleTester.run("padding-line-between-statements", rule, {
             ],
             errors: [MESSAGE_ALWAYS]
         },
+        {
+            code: "async function foo(){}\nfoo()",
+            output: "async function foo(){}\n\nfoo()",
+            options: [
+                { blankLine: "never", prev: "*", next: "*" },
+                { blankLine: "always", prev: "function", next: "*" }
+            ],
+            errors: [MESSAGE_ALWAYS]
+        },
 
         //----------------------------------------------------------------------
         // if
diff --git a/tests/lib/rules/require-atomic-updates.js b/tests/lib/rules/require-atomic-updates.js
new file mode 100644
index 000000000..eabd52149
--- /dev/null
+++ b/tests/lib/rules/require-atomic-updates.js
@@ -0,0 +1,143 @@
+/**
+ * @fileoverview disallow assignments that can lead to race conditions due to usage of `await` or `yield`
+ * @author Teddy Katz
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Requirements
+//------------------------------------------------------------------------------
+
+const rule = require("../../../lib/rules/require-atomic-updates");
+const RuleTester = require("../../../lib/testers/rule-tester");
+
+
+//------------------------------------------------------------------------------
+// Tests
+//------------------------------------------------------------------------------
+
+const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 2018 } });
+
+const VARIABLE_ERROR = {
+    messageId: "nonAtomicUpdate",
+    data: { value: "foo" },
+    type: "AssignmentExpression"
+};
+
+const STATIC_PROPERTY_ERROR = {
+    messageId: "nonAtomicUpdate",
+    data: { value: "foo.bar" },
+    type: "AssignmentExpression"
+};
+
+const COMPUTED_PROPERTY_ERROR = {
+    messageId: "nonAtomicUpdate",
+    data: { value: "foo[bar].baz" },
+    type: "AssignmentExpression"
+};
+
+ruleTester.run("require-atomic-updates", rule, {
+
+    valid: [
+        "let foo; async function x() { foo += bar; }",
+        "let foo; async function x() { foo = foo + bar; }",
+        "let foo; async function x() { foo = await bar + foo; }",
+        "async function x() { let foo; foo += await bar; }",
+        "let foo; async function x() { foo = (await result)(foo); }",
+        "let foo; async function x() { foo = bar(await something, foo) }",
+        "function* x() { let foo; foo += yield bar; }",
+        "const foo = {}; async function x() { foo.bar = await baz; }",
+        "const foo = []; async function x() { foo[x] += 1;  }",
+        "let foo; function* x() { foo = bar + foo; }",
+        "async function x() { let foo; bar(() => baz += 1); foo += await amount; }",
+        "let foo; async function x() { foo = condition ? foo : await bar; }",
+        "async function x() { let foo; bar(() => { let foo; blah(foo); }); foo += await result; }"
+    ],
+
+    invalid: [
+        {
+            code: "let foo; async function x() { foo += await amount; }",
+            errors: [{ messageId: "nonAtomicUpdate", data: { value: "foo" } }]
+        },
+        {
+            code: "let foo; async function x() { while (condition) { foo += await amount; } }",
+            errors: [VARIABLE_ERROR]
+        },
+        {
+            code: "let foo; async function x() { foo = foo + await amount; }",
+            errors: [VARIABLE_ERROR]
+        },
+        {
+            code: "let foo; async function x() { foo = foo + (bar ? baz : await amount); }",
+            errors: [VARIABLE_ERROR]
+        },
+        {
+            code: "let foo; async function x() { foo = foo + (bar ? await amount : baz); }",
+            errors: [VARIABLE_ERROR]
+        },
+        {
+            code: "let foo; async function x() { foo = condition ? foo + await amount : somethingElse; }",
+            errors: [VARIABLE_ERROR]
+        },
+        {
+            code: "let foo; async function x() { foo = (condition ? foo : await bar) + await bar; }",
+            errors: [VARIABLE_ERROR]
+        },
+        {
+            code: "let foo; async function x() { foo += bar + await amount; }",
+            errors: [VARIABLE_ERROR]
+        },
+        {
+            code: "async function x() { let foo; bar(() => foo); foo += await amount; }",
+            errors: [VARIABLE_ERROR]
+        },
+        {
+            code: "let foo; function* x() { foo += yield baz }",
+            errors: [VARIABLE_ERROR]
+        },
+        {
+            code: "let foo; async function x() { foo = bar(foo, await something) }",
+            errors: [VARIABLE_ERROR]
+        },
+        {
+            code: "const foo = {}; async function x() { foo.bar += await baz }",
+            errors: [STATIC_PROPERTY_ERROR]
+        },
+        {
+            code: "const foo = []; async function x() { foo[bar].baz += await result;  }",
+            errors: [COMPUTED_PROPERTY_ERROR]
+        },
+        {
+            code: "let foo; async function* x() { foo = (yield foo) + await bar; }",
+            errors: [VARIABLE_ERROR]
+        },
+        {
+            code: "let foo; async function x() { foo = foo + await result(foo); }",
+            errors: [VARIABLE_ERROR]
+        },
+        {
+            code: "let foo; async function x() { foo = await result(foo, await somethingElse); }",
+            errors: [VARIABLE_ERROR]
+        },
+        {
+            code: "function* x() { let foo; yield async function y() { foo += await bar; } }",
+            errors: [VARIABLE_ERROR]
+        },
+        {
+            code: "let foo; async function* x() { foo = await foo + (yield bar); }",
+            errors: [VARIABLE_ERROR]
+        },
+        {
+            code: "let foo; async function x() { foo = bar + await foo; }",
+            errors: [VARIABLE_ERROR]
+        },
+        {
+            code: "let foo = {}; async function x() { foo[bar].baz = await (foo.bar += await foo[bar].baz) }",
+            errors: [COMPUTED_PROPERTY_ERROR, STATIC_PROPERTY_ERROR]
+        },
+        {
+            code: "async function x() { foo += await bar; }",
+            errors: [VARIABLE_ERROR]
+        }
+    ]
+});
diff --git a/tests/lib/rules/require-unicode-regexp.js b/tests/lib/rules/require-unicode-regexp.js
new file mode 100644
index 000000000..a261c86e3
--- /dev/null
+++ b/tests/lib/rules/require-unicode-regexp.js
@@ -0,0 +1,90 @@
+/**
+ * @fileoverview Tests for require-unicode-regexp rule.
+ * @author Toru Nagashima
+ */
+
+"use strict";
+
+//------------------------------------------------------------------------------
+// Requirements
+//------------------------------------------------------------------------------
+
+const rule = require("../../../lib/rules/require-unicode-regexp");
+const RuleTester = require("../../../lib/testers/rule-tester");
+
+//------------------------------------------------------------------------------
+// Tests
+//------------------------------------------------------------------------------
+
+const ruleTester = new RuleTester({
+    parserOptions: { ecmaVersion: 2015 }
+});
+
+ruleTester.run("require-unicode-regexp", rule, {
+    valid: [
+        "/foo/u",
+        "/foo/gimuy",
+        "RegExp('', 'u')",
+        "new RegExp('', 'u')",
+        "RegExp('', 'gimuy')",
+        "new RegExp('', 'gimuy')",
+        "const flags = 'u'; new RegExp('', flags)",
+        "const flags = 'g'; new RegExp('', flags + 'u')",
+        "const flags = 'gimu'; new RegExp('foo', flags.slice(1))",
+        "new RegExp('', flags)",
+        "function f(flags) { return new RegExp('', flags) }",
+        "function f(RegExp) { return new RegExp('foo') }"
+    ],
+    invalid: [
+        {
+            code: "/foo/",
+            errors: [{ messageId: "requireUFlag" }]
+        },
+        {
+            code: "/foo/gimy",
+            errors: [{ messageId: "requireUFlag" }]
+        },
+        {
+            code: "RegExp('foo')",
+            errors: [{ messageId: "requireUFlag" }]
+        },
+        {
+            code: "RegExp('foo', '')",
+            errors: [{ messageId: "requireUFlag" }]
+        },
+        {
+            code: "RegExp('foo', 'gimy')",
+            errors: [{ messageId: "requireUFlag" }]
+        },
+        {
+            code: "new RegExp('foo')",
+            errors: [{ messageId: "requireUFlag" }]
+        },
+        {
+            code: "new RegExp('foo', '')",
+            errors: [{ messageId: "requireUFlag" }]
+        },
+        {
+            code: "new RegExp('foo', 'gimy')",
+            errors: [{ messageId: "requireUFlag" }]
+        },
+        {
+            code: "const flags = 'gi'; new RegExp('foo', flags)",
+            errors: [{ messageId: "requireUFlag" }]
+        },
+        {
+            code: "const flags = 'gimu'; new RegExp('foo', flags.slice(0, -1))",
+            errors: [{ messageId: "requireUFlag" }]
+        },
+        {
+            code: "new window.RegExp('foo')",
+            errors: [{ messageId: "requireUFlag" }],
+            env: { browser: true }
+        },
+        {
+            code: "new global.RegExp('foo')",
+            errors: [{ messageId: "requireUFlag" }],
+            env: { node: true }
+        }
+    ]
+});
diff --git a/tests/lib/ast-utils.js b/tests/lib/util/ast-utils.js
similarity index 99%
rename from tests/lib/ast-utils.js
rename to tests/lib/util/ast-utils.js
index c728b8457..b2ff37010 100644
--- a/tests/lib/ast-utils.js
+++ b/tests/lib/util/ast-utils.js
@@ -11,9 +11,9 @@
 
 const assert = require("chai").assert,
     espree = require("espree"),
-    astUtils = require("../../lib/ast-utils"),
-    Linter = require("../../lib/linter"),
-    SourceCode = require("../../lib/util/source-code");
+    astUtils = require("../../../lib/util/ast-utils"),
+    Linter = require("../../../lib/linter"),
+    SourceCode = require("../../../lib/util/source-code");
 
 //------------------------------------------------------------------------------
 // Tests
diff --git a/tests/lib/file-finder.js b/tests/lib/util/file-finder.js
similarity index 98%
rename from tests/lib/file-finder.js
rename to tests/lib/util/file-finder.js
index 5e9d7907a..e2a9e147f 100644
--- a/tests/lib/file-finder.js
+++ b/tests/lib/util/file-finder.js
@@ -11,14 +11,14 @@
 
 const assert = require("chai").assert,
     path = require("path"),
-    FileFinder = require("../../lib/file-finder.js");
+    FileFinder = require("../../../lib/util/file-finder.js");
 
 //------------------------------------------------------------------------------
 // Tests
 //------------------------------------------------------------------------------
 
 describe("FileFinder", () => {
-    const fixtureDir = path.resolve(__dirname, "..", "fixtures"),
+    const fixtureDir = path.resolve(__dirname, "../..", "fixtures"),
         fileFinderDir = path.join(fixtureDir, "file-finder"),
         subdir = path.join(fileFinderDir, "subdir"),
         subsubdir = path.join(subdir, "subsubdir"),
diff --git a/tests/lib/util/glob-util.js b/tests/lib/util/glob-utils.js
similarity index 86%
rename from tests/lib/util/glob-util.js
rename to tests/lib/util/glob-utils.js
index afa7d3f70..58bf8883f 100644
--- a/tests/lib/util/glob-util.js
+++ b/tests/lib/util/glob-utils.js
@@ -12,7 +12,7 @@ const assert = require("chai").assert,
     path = require("path"),
     os = require("os"),
     sh = require("shelljs"),
-    globUtil = require("../../../lib/util/glob-util"),
+    globUtils = require("../../../lib/util/glob-utils"),
     fs = require("fs");
 
 //------------------------------------------------------------------------------
@@ -34,7 +34,7 @@ function getFixturePath(...args) {
 // Tests
 //------------------------------------------------------------------------------
 
-describe("globUtil", () => {
+describe("globUtils", () => {
 
     before(() => {
         fixtureDir = `${os.tmpdir()}/eslint/tests/fixtures/`;
@@ -53,7 +53,7 @@ describe("globUtil", () => {
             const opts = {
                 cwd: getFixturePath("glob-util")
             };
-            const result = globUtil.resolveFileGlobPatterns(patterns, opts);
+            const result = globUtils.resolveFileGlobPatterns(patterns, opts);
 
             assert.deepStrictEqual(result, ["one-js-file/**/*.js"]);
         });
@@ -64,7 +64,7 @@ describe("globUtil", () => {
                 cwd: getFixturePath("glob-util"),
                 globInputPaths: false
             };
-            const result = globUtil.resolveFileGlobPatterns(patterns, opts);
+            const result = globUtils.resolveFileGlobPatterns(patterns, opts);
 
             assert.deepStrictEqual(result, ["one-js-file"]);
         });
@@ -74,7 +74,7 @@ describe("globUtil", () => {
             const opts = {
                 cwd: getFixturePath("glob-util")
             };
-            const result = globUtil.resolveFileGlobPatterns(patterns, opts);
+            const result = globUtils.resolveFileGlobPatterns(patterns, opts);
             const expected = [`${getFixturePath("glob-util", "one-js-file").replace(/\\/g, "/")}/**/*.js`];
 
             assert.deepStrictEqual(result, expected);
@@ -86,7 +86,7 @@ describe("globUtil", () => {
                 cwd: getFixturePath("glob-util"),
                 extensions: [".jsx"]
             };
-            const result = globUtil.resolveFileGlobPatterns(patterns, opts);
+            const result = globUtils.resolveFileGlobPatterns(patterns, opts);
 
             assert.deepStrictEqual(result, ["one-js-file/**/*.jsx"]);
         });
@@ -97,7 +97,7 @@ describe("globUtil", () => {
                 cwd: getFixturePath("glob-util"),
                 extensions: [".jsx", ".js"]
             };
-            const result = globUtil.resolveFileGlobPatterns(patterns, opts);
+            const result = globUtils.resolveFileGlobPatterns(patterns, opts);
 
             assert.deepStrictEqual(result, ["one-js-file/**/*.{jsx,js}"]);
         });
@@ -107,7 +107,7 @@ describe("globUtil", () => {
             const opts = {
                 cwd: getFixturePath("glob-util")
             };
-            const result = globUtil.resolveFileGlobPatterns(patterns, opts);
+            const result = globUtils.resolveFileGlobPatterns(patterns, opts);
 
             assert.deepStrictEqual(result, ["one-js-file/**/*.js", "two-js-files/**/*.js"]);
         });
@@ -117,7 +117,7 @@ describe("globUtil", () => {
             const opts = {
                 cwd: getFixturePath("glob-util")
             };
-            const result = globUtil.resolveFileGlobPatterns(patterns, opts);
+            const result = globUtils.resolveFileGlobPatterns(patterns, opts);
 
             assert.deepStrictEqual(result, ["one-js-file/**/*.js"]);
         });
@@ -127,7 +127,7 @@ describe("globUtil", () => {
             const opts = {
                 cwd: getFixturePath("glob-util")
             };
-            const result = globUtil.resolveFileGlobPatterns(patterns, opts);
+            const result = globUtils.resolveFileGlobPatterns(patterns, opts);
 
             assert.deepStrictEqual(result, ["one-js-file/**/*.js"]);
         });
@@ -137,7 +137,7 @@ describe("globUtil", () => {
             const opts = {
                 cwd: getFixturePath("glob-util")
             };
-            const result = globUtil.resolveFileGlobPatterns(patterns, opts);
+            const result = globUtils.resolveFileGlobPatterns(patterns, opts);
 
             assert.deepStrictEqual(result, ["some-file.js"]);
         });
@@ -147,7 +147,7 @@ describe("globUtil", () => {
             const opts = {
                 cwd: getFixturePath()
             };
-            const result = globUtil.resolveFileGlobPatterns(patterns, opts);
+            const result = globUtils.resolveFileGlobPatterns(patterns, opts);
 
             assert.deepStrictEqual(result, ["one-js-file/example.js"]);
         });
@@ -157,7 +157,7 @@ describe("globUtil", () => {
 
         it("should return an array with a resolved (absolute) filename", () => {
             const patterns = [getFixturePath("glob-util", "one-js-file", "**/*.js")];
-            const result = globUtil.listFilesToProcess(patterns, {
+            const result = globUtils.listFilesToProcess(patterns, {
                 cwd: getFixturePath()
             });
 
@@ -169,7 +169,7 @@ describe("globUtil", () => {
 
         it("should return an array with a unmodified filename", () => {
             const patterns = [getFixturePath("glob-util", "one-js-file", "**/*.js")];
-            const result = globUtil.listFilesToProcess(patterns, {
+            const result = globUtils.listFilesToProcess(patterns, {
                 cwd: getFixturePath(),
                 globInputPaths: false
             });
@@ -182,7 +182,7 @@ describe("globUtil", () => {
 
         it("should return all files matching a glob pattern", () => {
             const patterns = [getFixturePath("glob-util", "two-js-files", "**/*.js")];
-            const result = globUtil.listFilesToProcess(patterns, {
+            const result = globUtils.listFilesToProcess(patterns, {
                 cwd: getFixturePath()
             });
 
@@ -201,7 +201,7 @@ describe("globUtil", () => {
                 getFixturePath("glob-util", "two-js-files", "**/*.js"),
                 getFixturePath("glob-util", "one-js-file", "**/*.js")
             ];
-            const result = globUtil.listFilesToProcess(patterns, {
+            const result = globUtils.listFilesToProcess(patterns, {
                 cwd: getFixturePath()
             });
 
@@ -221,7 +221,7 @@ describe("globUtil", () => {
             const patterns = [getFixturePath("glob-util", "hidden", "**/*.js")];
 
             assert.throws(() => {
-                globUtil.listFilesToProcess(patterns, {
+                globUtils.listFilesToProcess(patterns, {
                     cwd: getFixturePath()
                 });
             }, `All files matched by '${patterns[0]}' are ignored.`);
@@ -229,7 +229,7 @@ describe("globUtil", () => {
 
         it("should return hidden files if included in glob pattern", () => {
             const patterns = [getFixturePath("glob-util", "hidden", "**/.*.js")];
-            const result = globUtil.listFilesToProcess(patterns, {
+            const result = globUtils.listFilesToProcess(patterns, {
                 cwd: getFixturePath()
             });
 
@@ -246,7 +246,7 @@ describe("globUtil", () => {
             const patterns = [directory];
 
             assert.throws(() => {
-                globUtil.listFilesToProcess(patterns, {
+                globUtils.listFilesToProcess(patterns, {
                     cwd: getFixturePath()
                 });
             }, `All files matched by '${directory}' are ignored.`);
@@ -255,7 +255,7 @@ describe("globUtil", () => {
         it("should ignore and warn for default ignored files when passed explicitly", () => {
             const filename = getFixturePath("glob-util", "hidden", ".foo.js");
             const patterns = [filename];
-            const result = globUtil.listFilesToProcess(patterns, {
+            const result = globUtils.listFilesToProcess(patterns, {
                 cwd: getFixturePath()
             });
 
@@ -268,7 +268,7 @@ describe("globUtil", () => {
             const patterns = [directory];
 
             assert.throws(() => {
-                globUtil.listFilesToProcess(patterns, {
+                globUtils.listFilesToProcess(patterns, {
                     cwd: getFixturePath(),
                     ignore: false
                 });
@@ -278,7 +278,7 @@ describe("globUtil", () => {
         it("should not ignore default ignored files when passed explicitly if ignore is false", () => {
             const filename = getFixturePath("glob-util", "hidden", ".foo.js");
             const patterns = [filename];
-            const result = globUtil.listFilesToProcess(patterns, {
+            const result = globUtils.listFilesToProcess(patterns, {
                 cwd: getFixturePath(),
                 ignore: false
             });
@@ -292,7 +292,7 @@ describe("globUtil", () => {
             const patterns = [filename];
 
             assert.throws(() => {
-                globUtil.listFilesToProcess(patterns, {
+                globUtils.listFilesToProcess(patterns, {
                     cwd: getFixturePath(),
                     allowMissingGlobs: true
                 });
@@ -304,7 +304,7 @@ describe("globUtil", () => {
             const patterns = [filename];
 
             assert.throws(() => {
-                globUtil.listFilesToProcess(patterns, {
+                globUtils.listFilesToProcess(patterns, {
                     cwd: getFixturePath()
                 });
             }, `No files matching '${filename}' were found.`);
@@ -315,7 +315,7 @@ describe("globUtil", () => {
             const options = { ignore: true, ignorePath: getFixturePath("glob-util", "ignored", ".eslintignore") };
 
             assert.throws(() => {
-                globUtil.listFilesToProcess([pattern], options);
+                globUtils.listFilesToProcess([pattern], options);
             }, `All files matched by '${pattern}' are ignored.`);
         });
 
@@ -325,14 +325,14 @@ describe("globUtil", () => {
             const patterns = ["tests/fixtures/glob-util/ignored/**/*.js"];
 
             assert.throws(() => {
-                globUtil.listFilesToProcess(patterns);
+                globUtils.listFilesToProcess(patterns);
             }, `No files matching '${patterns[0]}' were found.`);
         });
 
         it("should return an ignored file, if ignore option is turned off", () => {
             const options = { ignore: false };
             const patterns = [getFixturePath("glob-util", "ignored", "**/*.js")];
-            const result = globUtil.listFilesToProcess(patterns, options);
+            const result = globUtils.listFilesToProcess(patterns, options);
 
             assert.strictEqual(result.length, 1);
         });
@@ -342,7 +342,7 @@ describe("globUtil", () => {
             const patterns = [getFixturePath("glob-util", "ignored", "**/*.js")];
 
             assert.throws(() => {
-                globUtil.listFilesToProcess(patterns, options);
+                globUtils.listFilesToProcess(patterns, options);
             }, `All files matched by '${patterns[0]}' are ignored.`);
         });
 
@@ -351,7 +351,7 @@ describe("globUtil", () => {
             const patterns = [getFixturePath("glob-util", "ignored", "**/*.js")];
 
             assert.throws(() => {
-                globUtil.listFilesToProcess(patterns, options);
+                globUtils.listFilesToProcess(patterns, options);
             }, `All files matched by '${patterns[0]}' are ignored.`);
         });
 
@@ -360,7 +360,7 @@ describe("globUtil", () => {
                 getFixturePath("glob-util", "one-js-file", "**/*.js"),
                 getFixturePath("glob-util", "one-js-file", "baz.js")
             ];
-            const result = globUtil.listFilesToProcess(patterns, {
+            const result = globUtils.listFilesToProcess(patterns, {
                 cwd: path.join(fixtureDir, "..")
             });
 
@@ -376,7 +376,7 @@ describe("globUtil", () => {
             const options = { ignore: true, ignorePattern: "foo.js", cwd: getFixturePath() };
             const filename = getFixturePath("glob-util", "ignored", "foo.js");
             const patterns = [filename];
-            const result = globUtil.listFilesToProcess(patterns, options);
+            const result = globUtils.listFilesToProcess(patterns, options);
 
             assert.strictEqual(result.length, 1);
             assert.deepStrictEqual(result, [
@@ -388,7 +388,7 @@ describe("globUtil", () => {
             const options = { cwd: getFixturePath("glob-util") };
             const glob = getFixturePath("glob-util", "**/*.js");
             const patterns = [glob];
-            const result = globUtil.listFilesToProcess(patterns, options);
+            const result = globUtils.listFilesToProcess(patterns, options);
             const resultFilenames = result.map(resultObj => resultObj.filename);
 
             assert.notInclude(resultFilenames, getFixturePath("glob-util", "node_modules", "dependency.js"));
@@ -398,7 +398,7 @@ describe("globUtil", () => {
             const options = { ignorePattern: "!/node_modules/dependency.js", cwd: getFixturePath("glob-util") };
             const glob = getFixturePath("glob-util", "**/*.js");
             const patterns = [glob];
-            const result = globUtil.listFilesToProcess(patterns, options);
+            const result = globUtils.listFilesToProcess(patterns, options);
             const unignoredFilename = getFixturePath("glob-util", "node_modules", "dependency.js");
 
             assert.includeDeepMembers(result, [{ filename: unignoredFilename, ignored: false }]);
diff --git a/tests/lib/util/npm-util.js b/tests/lib/util/npm-utils.js
similarity index 82%
rename from tests/lib/util/npm-util.js
rename to tests/lib/util/npm-utils.js
index b0237c464..1b07f3715 100644
--- a/tests/lib/util/npm-util.js
+++ b/tests/lib/util/npm-utils.js
@@ -11,7 +11,7 @@
 const assert = require("chai").assert,
     spawn = require("cross-spawn"),
     sinon = require("sinon"),
-    npmUtil = require("../../../lib/util/npm-util"),
+    npmUtils = require("../../../lib/util/npm-utils"),
     log = require("../../../lib/util/logging"),
     mockFs = require("mock-fs");
 
@@ -19,7 +19,7 @@ const assert = require("chai").assert,
 // Tests
 //------------------------------------------------------------------------------
 
-describe("npmUtil", () => {
+describe("npmUtils", () => {
 
     let sandbox;
 
@@ -36,7 +36,7 @@ describe("npmUtil", () => {
         let installStatus;
 
         before(() => {
-            installStatus = npmUtil.checkDevDeps(["debug", "mocha", "notarealpackage", "jshint"]);
+            installStatus = npmUtils.checkDevDeps(["debug", "mocha", "notarealpackage", "jshint"]);
         });
 
         it("should not find a direct dependency of the project", () => {
@@ -56,7 +56,7 @@ describe("npmUtil", () => {
         });
 
         it("should return false for a single, non-existent package", () => {
-            installStatus = npmUtil.checkDevDeps(["notarealpackage"]);
+            installStatus = npmUtils.checkDevDeps(["notarealpackage"]);
             assert.isFalse(installStatus.notarealpackage);
         });
 
@@ -66,7 +66,7 @@ describe("npmUtil", () => {
             });
 
             // Should not throw.
-            npmUtil.checkDevDeps(["some-package"]);
+            npmUtils.checkDevDeps(["some-package"]);
         });
 
         it("should throw with message when parsing invalid package.json", () => {
@@ -76,7 +76,7 @@ describe("npmUtil", () => {
 
             assert.throws(() => {
                 try {
-                    npmUtil.checkDevDeps(["some-package"]);
+                    npmUtils.checkDevDeps(["some-package"]);
                 } catch (error) {
                     assert.strictEqual(error.messageTemplate, "failed-to-read-json");
                     throw error;
@@ -89,7 +89,7 @@ describe("npmUtil", () => {
         let installStatus;
 
         before(() => {
-            installStatus = npmUtil.checkDeps(["debug", "mocha", "notarealpackage", "jshint"]);
+            installStatus = npmUtils.checkDeps(["debug", "mocha", "notarealpackage", "jshint"]);
         });
 
         afterEach(() => {
@@ -113,13 +113,13 @@ describe("npmUtil", () => {
         });
 
         it("should return false for a single, non-existent package", () => {
-            installStatus = npmUtil.checkDeps(["notarealpackage"]);
+            installStatus = npmUtils.checkDeps(["notarealpackage"]);
             assert.isFalse(installStatus.notarealpackage);
         });
 
         it("should throw if no package.json can be found", () => {
             assert.throws(() => {
-                installStatus = npmUtil.checkDeps(["notarealpackage"], "/fakepath");
+                installStatus = npmUtils.checkDeps(["notarealpackage"], "/fakepath");
             }, "Could not find a package.json file");
         });
 
@@ -129,7 +129,7 @@ describe("npmUtil", () => {
             });
 
             // Should not throw.
-            npmUtil.checkDeps(["some-package"]);
+            npmUtils.checkDeps(["some-package"]);
         });
 
         it("should throw with message when parsing invalid package.json", () => {
@@ -139,7 +139,7 @@ describe("npmUtil", () => {
 
             assert.throws(() => {
                 try {
-                    npmUtil.checkDeps(["some-package"]);
+                    npmUtils.checkDeps(["some-package"]);
                 } catch (error) {
                     assert.strictEqual(error.messageTemplate, "failed-to-read-json");
                     throw error;
@@ -158,12 +158,12 @@ describe("npmUtil", () => {
                 "package.json": "{ \"file\": \"contents\" }"
             });
 
-            assert.strictEqual(npmUtil.checkPackageJson(), true);
+            assert.strictEqual(npmUtils.checkPackageJson(), true);
         });
 
         it("should return false if package.json does not exist", () => {
             mockFs({});
-            assert.strictEqual(npmUtil.checkPackageJson(), false);
+            assert.strictEqual(npmUtils.checkPackageJson(), false);
         });
     });
 
@@ -171,7 +171,7 @@ describe("npmUtil", () => {
         it("should invoke npm to install a single desired package", () => {
             const stub = sandbox.stub(spawn, "sync").returns({ stdout: "" });
 
-            npmUtil.installSyncSaveDev("desired-package");
+            npmUtils.installSyncSaveDev("desired-package");
             assert(stub.calledOnce);
             assert.strictEqual(stub.firstCall.args[0], "npm");
             assert.deepStrictEqual(stub.firstCall.args[1], ["i", "--save-dev", "desired-package"]);
@@ -181,7 +181,7 @@ describe("npmUtil", () => {
         it("should accept an array of packages to install", () => {
             const stub = sandbox.stub(spawn, "sync").returns({ stdout: "" });
 
-            npmUtil.installSyncSaveDev(["first-package", "second-package"]);
+            npmUtils.installSyncSaveDev(["first-package", "second-package"]);
             assert(stub.calledOnce);
             assert.strictEqual(stub.firstCall.args[0], "npm");
             assert.deepStrictEqual(stub.firstCall.args[1], ["i", "--save-dev", "first-package", "second-package"]);
@@ -190,14 +190,14 @@ describe("npmUtil", () => {
 
         it("should log an error message if npm throws ENOENT error", () => {
             const logErrorStub = sandbox.stub(log, "error");
-            const npmUtilStub = sandbox.stub(spawn, "sync").returns({ error: { code: "ENOENT" } });
+            const npmUtilsStub = sandbox.stub(spawn, "sync").returns({ error: { code: "ENOENT" } });
 
-            npmUtil.installSyncSaveDev("some-package");
+            npmUtils.installSyncSaveDev("some-package");
 
             assert(logErrorStub.calledOnce);
 
             logErrorStub.restore();
-            npmUtilStub.restore();
+            npmUtilsStub.restore();
         });
     });
 
@@ -205,7 +205,7 @@ describe("npmUtil", () => {
         it("should execute 'npm show --json <packageName> peerDependencies' command", () => {
             const stub = sandbox.stub(spawn, "sync").returns({ stdout: "" });
 
-            npmUtil.fetchPeerDependencies("desired-package");
+            npmUtils.fetchPeerDependencies("desired-package");
             assert(stub.calledOnce);
             assert.strictEqual(stub.firstCall.args[0], "npm");
             assert.deepStrictEqual(stub.firstCall.args[1], ["show", "--json", "desired-package", "peerDependencies"]);
@@ -215,7 +215,7 @@ describe("npmUtil", () => {
         it("should return null if npm throws ENOENT error", () => {
             const stub = sandbox.stub(spawn, "sync").returns({ error: { code: "ENOENT" } });
 
-            const peerDependencies = npmUtil.fetchPeerDependencies("desired-package");
+            const peerDependencies = npmUtils.fetchPeerDependencies("desired-package");
 
             assert.isNull(peerDependencies);
 
diff --git a/tests/lib/util/path-util.js b/tests/lib/util/path-utils.js
similarity index 81%
rename from tests/lib/util/path-util.js
rename to tests/lib/util/path-utils.js
index bfb6efa5c..f0e1061f5 100644
--- a/tests/lib/util/path-util.js
+++ b/tests/lib/util/path-utils.js
@@ -11,7 +11,7 @@
 const path = require("path"),
     assert = require("chai").assert,
     sinon = require("sinon"),
-    pathUtil = require("../../../lib/util/path-util");
+    pathUtils = require("../../../lib/util/path-utils");
 
 //------------------------------------------------------------------------------
 // Tests
@@ -23,28 +23,28 @@ describe("pathUtil", () => {
 
         it("should remove a leading './'", () => {
             const input = "./relative/file/path.js";
-            const result = pathUtil.convertPathToPosix(input);
+            const result = pathUtils.convertPathToPosix(input);
 
             assert.strictEqual(result, "relative/file/path.js");
         });
 
         it("should remove interior '../'", () => {
             const input = "./relative/file/../path.js";
-            const result = pathUtil.convertPathToPosix(input);
+            const result = pathUtils.convertPathToPosix(input);
 
             assert.strictEqual(result, "relative/path.js");
         });
 
         it("should not remove a leading '../'", () => {
             const input = "../parent/file/path.js";
-            const result = pathUtil.convertPathToPosix(input);
+            const result = pathUtils.convertPathToPosix(input);
 
             assert.strictEqual(result, "../parent/file/path.js");
         });
 
         it("should convert windows path seperators into posix style path seperators", () => {
             const input = "windows\\style\\path.js";
-            const result = pathUtil.convertPathToPosix(input);
+            const result = pathUtils.convertPathToPosix(input);
 
             assert.strictEqual(result, "windows/style/path.js");
         });
@@ -56,7 +56,7 @@ describe("pathUtil", () => {
         it("should return a path relative to the provided base path", () => {
             const filePath = "/absolute/file/path.js";
             const basePath = "/absolute/";
-            const result = pathUtil.getRelativePath(filePath, basePath);
+            const result = pathUtils.getRelativePath(filePath, basePath);
 
             assert.strictEqual(result, path.normalize("file/path.js"));
         });
@@ -66,7 +66,7 @@ describe("pathUtil", () => {
             const basePath = "somewhere/";
 
             assert.throws(() => {
-                pathUtil.getRelativePath(filePath, basePath);
+                pathUtils.getRelativePath(filePath, basePath);
             });
         });
 
@@ -75,7 +75,7 @@ describe("pathUtil", () => {
             const basePath = "/absolute/file";
 
             sinon.stub(process, "cwd").returns("/absolute/");
-            const result = pathUtil.getRelativePath(filePath, basePath);
+            const result = pathUtils.getRelativePath(filePath, basePath);
 
             assert.strictEqual(result, "path.js");
 
@@ -84,7 +84,7 @@ describe("pathUtil", () => {
 
         it("should strip a leading '/' if no baseDir is provided", () => {
             const filePath = "/absolute/file/path.js";
-            const result = pathUtil.getRelativePath(filePath);
+            const result = pathUtils.getRelativePath(filePath);
 
             assert.strictEqual(result, "absolute/file/path.js");
         });
diff --git a/tests/lib/util/source-code-util.js b/tests/lib/util/source-code-utils.js
similarity index 98%
rename from tests/lib/util/source-code-util.js
rename to tests/lib/util/source-code-utils.js
index 1a406e5d3..7d3350a0d 100644
--- a/tests/lib/util/source-code-util.js
+++ b/tests/lib/util/source-code-utils.js
@@ -15,7 +15,7 @@ const path = require("path"),
     assert = require("chai").assert,
     sinon = require("sinon"),
     sh = require("shelljs"),
-    globUtil = require("../../../lib/util/glob-util"),
+    globUtils = require("../../../lib/util/glob-utils"),
     SourceCode = require("../../../lib/util/source-code");
 
 const proxyquire = require("proxyquire").noCallThru().noPreserveCache();
@@ -63,7 +63,7 @@ describe("SourceCodeUtil", () => {
     });
 
     beforeEach(() => {
-        getSourceCodeOfFiles = proxyquire("../../../lib/util/source-code-util", requireStubs).getSourceCodeOfFiles;
+        getSourceCodeOfFiles = proxyquire("../../../lib/util/source-code-utils", requireStubs).getSourceCodeOfFiles;
     });
 
     afterEach(() => {
@@ -139,7 +139,7 @@ describe("SourceCodeUtil", () => {
 
         it("should use default options if none are provided", () => {
             const filename = getFixturePath("foo.js");
-            const spy = sinon.spy(globUtil, "resolveFileGlobPatterns");
+            const spy = sinon.spy(globUtils, "resolveFileGlobPatterns");
 
             getSourceCodeOfFiles(filename);
             assert(spy.called);
diff --git a/tests/lib/util/source-code.js b/tests/lib/util/source-code.js
index 9d7adac04..665176522 100644
--- a/tests/lib/util/source-code.js
+++ b/tests/lib/util/source-code.js
@@ -16,7 +16,7 @@ const fs = require("fs"),
     leche = require("leche"),
     Linter = require("../../../lib/linter"),
     SourceCode = require("../../../lib/util/source-code"),
-    astUtils = require("../../../lib/ast-utils");
+    astUtils = require("../../../lib/util/ast-utils");
 
 //------------------------------------------------------------------------------
 // Helpers