Repository: eslint/eslint
Pull request #11435 (2019-02-23 19:06:59)

Chore: make config validator params more consistent
<!--
    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)**
move the function param `source` to be last, and defaults to `null`.
since it's not always necessary, as in some of the tests.

**Is there anything you'd like reviewers to focus on?**
no




Patch:
diff --git a/.eslintrc.js b/.eslintrc.js
index 780368769..86cc48017 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -1,18 +1,13 @@
 "use strict";
 
-const path = require("path");
-const rulesDirPlugin = require("eslint-plugin-rulesdir");
-
-rulesDirPlugin.RULES_DIR = path.join(__dirname, "tools/internal-rules");
-
 module.exports = {
     root: true,
     plugins: [
         "eslint-plugin",
-        "rulesdir"
+        "internal-rules"
     ],
     extends: [
-        "./packages/eslint-config-eslint/default.yml",
+        "eslint",
         "plugin:eslint-plugin/recommended"
     ],
     rules: {
@@ -24,24 +19,30 @@ module.exports = {
         "eslint-plugin/require-meta-type": "error",
         "eslint-plugin/test-case-property-ordering": "error",
         "eslint-plugin/test-case-shorthand-strings": "error",
-        "rulesdir/multiline-comment-style": "error"
+        "internal-rules/multiline-comment-style": "error"
     },
     overrides: [
         {
             files: ["lib/rules/*", "tools/internal-rules/*"],
+            excludedFiles: ["tools/internal-rules/index.js"],
             rules: {
-                "rulesdir/no-invalid-meta": "error",
-                "rulesdir/consistent-docs-description": "error"
+                "internal-rules/no-invalid-meta": "error",
+                "internal-rules/consistent-docs-description": "error"
 
                 /*
                  * TODO: enable it when all the rules using meta.messages
-                 * "rulesdir/consistent-meta-messages": "error"
+                 * "internal-rules/consistent-meta-messages": "error"
                  */
             }
+        }, {
+            files: ["tools/internal-rules/*"],
+            rules: {
+                "node/no-unpublished-require": "off"
+            }
         }, {
             files: ["lib/rules/*"],
             rules: {
-                "rulesdir/consistent-docs-url": "error"
+                "internal-rules/consistent-docs-url": "error"
             }
         }, {
             files: ["tests/**/*"],
diff --git a/.travis.yml b/.travis.yml
index 22decd59f..baf4d28fd 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -5,7 +5,7 @@ node_js:
     - "9"
     - "10"
     - "11"
-sudo: false
+
 branches:
     only:
     - master
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 89eb84613..115a7c3c5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,29 @@
+v5.15.1 - March 4, 2019
+
+* [`fe1a892`](https://github.com/eslint/eslint/commit/fe1a892f85b09c3d2fea05bef011530a678a6af5) Build: bundle espree (fixes eslint/eslint.github.io#546) (#11467) (薛定谔的猫)
+* [`458053b`](https://github.com/eslint/eslint/commit/458053b0b541f857bf233dacbde5ba80681820f8) Fix: avoid creating invalid regex in no-warning-comments (fixes #11471) (#11472) (Teddy Katz)
+
+v5.15.0 - March 1, 2019
+
+* [`4088c6c`](https://github.com/eslint/eslint/commit/4088c6c9d4578cd581ce8ff4385d90b58a75b755) Build: Remove path.resolve in webpack build (#11462) (Kevin Partington)
+* [`ec59ec0`](https://github.com/eslint/eslint/commit/ec59ec09c8d001b8c04f9edc09994e2b0d0af0f9) New: add rule "prefer-named-capture-group" (fixes #11381) (#11392) (Pig Fang)
+* [`a44f750`](https://github.com/eslint/eslint/commit/a44f75073306e5ea4e6722654009a99884fbca4f) Upgrade: eslint-scope@4.0.2 (#11461) (Teddy Katz)
+* [`d3ce611`](https://github.com/eslint/eslint/commit/d3ce611e1c705440ccbcae357f2194134d026541) Sponsors: Sync README with website (ESLint Jenkins)
+* [`ee88475`](https://github.com/eslint/eslint/commit/ee884754e4111e11994ff0df3f0c29e43e1dc3f2) Chore: add utils for rule tests (#11453) (薛定谔的猫)
+* [`d4824e4`](https://github.com/eslint/eslint/commit/d4824e46d7a6ca1618454d3c6198403382108123) Sponsors: Sync README with website (ESLint Jenkins)
+* [`6489518`](https://github.com/eslint/eslint/commit/64895185bde5233223648bcaf46f8deb72c9fb55) Fix: no-extra-parens crash when code is "((let))" (#11444) (Teddy Katz)
+* [`9d20de2`](https://github.com/eslint/eslint/commit/9d20de2b0ac756bd62888119b8e08c7441d8a5aa) Sponsors: Sync README with website (ESLint Jenkins)
+* [`3f14de4`](https://github.com/eslint/eslint/commit/3f14de458ba120e9c013f5fc7c6fe3e9b40c1460) Sponsors: Sync README with website (ESLint Jenkins)
+* [`3d6c770`](https://github.com/eslint/eslint/commit/3d6c7709d47e047b25d91ca1a77d6dab92313061) Sponsors: Sync README with website (ESLint Jenkins)
+* [`de5cbc5`](https://github.com/eslint/eslint/commit/de5cbc526b30405e742b35d85d04361529d49ed4) Update: remove invalid defaults from core rules (fixes #11415) (#11427) (Teddy Katz)
+* [`eb0650b`](https://github.com/eslint/eslint/commit/eb0650ba20cf9f9ad78dbaccfeb7e0e7ab56e31d) Build: fix linting errors on master (#11428) (Teddy Katz)
+* [`5018378`](https://github.com/eslint/eslint/commit/5018378131fd5190bbccca902c0cf4276ee1581a) Chore: enable require-unicode-regexp on ESLint codebase (#11422) (Teddy Katz)
+* [`f6ba633`](https://github.com/eslint/eslint/commit/f6ba633f56eca6be20fc4b0d9496a78b9498d578) Chore: lint all files in the repo at the same time (#11425) (Teddy Katz)
+* [`8f3d717`](https://github.com/eslint/eslint/commit/8f3d71754932669332ad7623bcc4c1aef3897125) Docs: Add non-attending TSC member info (#11411) (Nicholas C. Zakas)
+* [`ce0777d`](https://github.com/eslint/eslint/commit/ce0777da5bc167fe0c529158fd8216d3eaf11565) Docs: use more common spelling (#11417) (薛定谔的猫)
+* [`b9aabe3`](https://github.com/eslint/eslint/commit/b9aabe34311f6189b87c9d8a1aa40f3513fed773) Chore: run fuzzer along with unit tests (#11404) (Teddy Katz)
+* [`db0c5e2`](https://github.com/eslint/eslint/commit/db0c5e2a7f894b7cda71007b0ba43d7814b3fb2e) Build: switch from browserify to webpack (fixes #11366) (#11398) (Pig Fang)
+
 v5.14.1 - February 18, 2019
 
 * [`1d6e639`](https://github.com/eslint/eslint/commit/1d6e63930073e79e52890f552cc6e9a0646b7fb4) Fix: sort-keys throws Error at SpreadElement (fixes #11402) (#11403) (Krist Wongsuphasawat)
diff --git a/Makefile.js b/Makefile.js
index c34b1c8f2..bd6f46524 100644
--- a/Makefile.js
+++ b/Makefile.js
@@ -25,7 +25,8 @@ const lodash = require("lodash"),
     semver = require("semver"),
     ejs = require("ejs"),
     loadPerf = require("load-perf"),
-    yaml = require("js-yaml");
+    yaml = require("js-yaml"),
+    CLIEngine = require("./lib/cli-engine");
 
 const { cat, cd, cp, echo, exec, exit, find, ls, mkdir, pwd, rm, test } = require("shelljs");
 
@@ -53,7 +54,7 @@ const NODE = "node ", // intentional extra space
     NODE_MODULES = "./node_modules/",
     TEMP_DIR = "./tmp/",
     DEBUG_DIR = "./debug/",
-    BUILD_DIR = "./build/",
+    BUILD_DIR = "build",
     DOCS_DIR = "../eslint.github.io/docs",
     SITE_DIR = "../eslint.github.io/",
     PERF_TMP_DIR = path.join(TEMP_DIR, "eslint", "performance"),
@@ -440,8 +441,7 @@ function lintMarkdown(files) {
  * @returns {Object} Output from each formatter
  */
 function getFormatterResults() {
-    const CLIEngine = require("./lib/cli-engine"),
-        stripAnsi = require("strip-ansi");
+    const stripAnsi = require("strip-ansi");
 
     const formatterFiles = fs.readdirSync("./lib/formatters/"),
         cli = new CLIEngine({
@@ -580,6 +580,19 @@ target.test = function() {
 
     target.webpack();
 
+    const browserFileLintOutput = new CLIEngine({
+        useEslintrc: false,
+        ignore: false,
+        allowInlineConfig: false,
+        baseConfig: { parserOptions: { ecmaVersion: 5 } }
+    }).executeOnFiles([`${BUILD_DIR}/eslint.js`]);
+
+    if (browserFileLintOutput.errorCount > 0) {
+        echo(`error: Failed to lint ${BUILD_DIR}/eslint.js as ES5 code`);
+        echo(CLIEngine.getFormatter("stylish")(browserFileLintOutput.results));
+        errors++;
+    }
+
     lastReturn = exec(`${getBinFile("karma")} start karma.conf.js`);
     if (lastReturn.code !== 0) {
         errors++;
@@ -783,6 +796,7 @@ target.gensite = function(prereleaseVersion) {
         echo("> Updating the demos (Step 13)");
         target.webpack("production");
         cp("-f", "build/eslint.js", `${SITE_DIR}js/app/eslint.js`);
+        cp("-f", "build/espree.js", `${SITE_DIR}js/app/espree.js`);
     } else {
         echo("> Skipped updating the demos (Step 13)");
     }
@@ -795,7 +809,7 @@ target.gensite = function(prereleaseVersion) {
 };
 
 target.webpack = function(mode = "none") {
-    exec(`${getBinFile("webpack")} --mode=${mode} --output-path=${path.resolve(__dirname, BUILD_DIR)}`);
+    exec(`${getBinFile("webpack")} --mode=${mode} --output-path=${BUILD_DIR}`);
 };
 
 target.checkRuleFiles = function() {
diff --git a/README.md b/README.md
index e0ee6a74f..437794dc6 100644
--- a/README.md
+++ b/README.md
@@ -266,9 +266,9 @@ The following companies, organizations, and individuals support ESLint's ongoing
 <!-- NOTE: This section is autogenerated. Do not manually edit.-->
 <!--sponsorsstart-->
 <h3>Gold Sponsors</h3>
-<p><a href="https://code.facebook.com/projects/"><img src="https://images.opencollective.com/proxy/images/?src=https%3A%2F%2Fres.cloudinary.com%2Fopencollective%2Fimage%2Fupload%2Fv1508519428%2FS9gk78AS_400x400_fulq2l.jpg&height=96" alt="Facebook Open Source" height="96"></a> <a href="https://www.airbnb.com/"><img src="https://images.opencollective.com/proxy/images/?src=https%3A%2F%2Fopencollective-production.s3-us-west-1.amazonaws.com%2F098e3bd0-4d57-11e8-9324-0f6cc1f92bf1.png&height=96" alt="Airbnb" height="96"></a></p><h3>Silver Sponsors</h3>
+<p><a href="https://www.airbnb.com/"><img src="https://images.opencollective.com/proxy/images/?src=https%3A%2F%2Fopencollective-production.s3-us-west-1.amazonaws.com%2F098e3bd0-4d57-11e8-9324-0f6cc1f92bf1.png&height=96" alt="Airbnb" height="96"></a> <a href="https://code.facebook.com/projects/"><img src="https://images.opencollective.com/proxy/images/?src=https%3A%2F%2Fres.cloudinary.com%2Fopencollective%2Fimage%2Fupload%2Fv1508519428%2FS9gk78AS_400x400_fulq2l.jpg&height=96" alt="Facebook Open Source" height="96"></a> <a href="https://badoo.com/team?utm_source=eslint"><img src="https://images.opencollective.com/proxy/images/?src=https%3A%2F%2Fopencollective-production.s3-us-west-1.amazonaws.com%2Fbbdb9cc0-3b5d-11e9-9537-ad85092287b8.png&height=96" alt="Badoo" height="96"></a></p><h3>Silver Sponsors</h3>
 <p><a href="https://www.ampproject.org/"><img src="https://images.opencollective.com/proxy/images/?src=https%3A%2F%2Fopencollective-production.s3-us-west-1.amazonaws.com%2F68ed8b70-ebf2-11e6-9958-cb7e79408c56.png&height=96" alt="AMP Project" height="64"></a></p><h3>Bronze Sponsors</h3>
-<p><a href="http://faithlife.com/ref/about"><img src="https://images.opencollective.com/proxy/images/?src=https%3A%2F%2Flogo.clearbit.com%2Ffaithlife.com&height=96" alt="Faithlife" height="32"></a></p>
+<p><a href="http://faithlife.com/ref/about"><img src="https://images.opencollective.com/proxy/images/?src=https%3A%2F%2Flogo.clearbit.com%2Ffaithlife.com&height=96" alt="Faithlife" height="32"></a> <a href="https://jsheroes.io/"><img src="https://images.opencollective.com/proxy/images/?src=https%3A%2F%2Flogo.clearbit.com%2Fjsheroes.io&height=96" alt="JSHeroes " height="32"></a></p>
 <!--sponsorsend-->
 
 ## Technology Sponsors
diff --git a/docs/developer-guide/nodejs-api.md b/docs/developer-guide/nodejs-api.md
index 7b9ecb6ec..3d41f25b9 100644
--- a/docs/developer-guide/nodejs-api.md
+++ b/docs/developer-guide/nodejs-api.md
@@ -677,6 +677,7 @@ Retrieves a formatter, which you can then use to format a report object. The arg
 * "[table](../user-guide/formatters#table)"
 * "[tap](../user-guide/formatters#tap)"
 * "[unix](../user-guide/formatters#unix)"
+* "[visualstudio](../user-guide/formatters#visualstudio)"
 
 or the full path to a JavaScript file containing a custom formatter. You can also omit the argument to retrieve the default formatter.
 
diff --git a/docs/developer-guide/working-with-rules.md b/docs/developer-guide/working-with-rules.md
index 38c2a8319..d189d53ad 100644
--- a/docs/developer-guide/working-with-rules.md
+++ b/docs/developer-guide/working-with-rules.md
@@ -472,7 +472,7 @@ module.exports = {
 
 In the preceding example, the error level is assumed to be the first argument. It is followed by the first optional argument, a string which may be either `"always"` or `"never"`. The final optional argument is an object, which may have a Boolean property named `exceptRange`.
 
-To learn more about JSON Schema, we recommend looking at some [examples](http://json-schema.org/examples.html) to start, and also reading [Understanding JSON Schema](http://spacetelescope.github.io/understanding-json-schema/) (a free ebook).
+To learn more about JSON Schema, we recommend looking at some examples in [website](http://json-schema.org/learn/) to start, and also reading [Understanding JSON Schema](http://spacetelescope.github.io/understanding-json-schema/) (a free ebook).
 
 **Note:** Currently you need to use full JSON Schema object rather than array in case your schema has references ($ref), because in case of array format ESLint transforms this array into a single schema without updating references that makes them incorrect (they are ignored).
 
diff --git a/docs/maintainer-guide/README.md b/docs/maintainer-guide/README.md
index 19c1fb9ee..941ad5599 100644
--- a/docs/maintainer-guide/README.md
+++ b/docs/maintainer-guide/README.md
@@ -17,3 +17,7 @@ Describes how to do an ESLint project release.
 ## [Governance](governance.md)
 
 Describes the governance policy for ESLint, including the rights and privileges of individuals inside the project.
+
+## [Working Groups](working-groups.md)
+
+Describes how working groups are created and how they function within the ESLint project.
diff --git a/docs/maintainer-guide/working-groups.md b/docs/maintainer-guide/working-groups.md
new file mode 100644
index 000000000..d6d22fb6c
--- /dev/null
+++ b/docs/maintainer-guide/working-groups.md
@@ -0,0 +1,22 @@
+# Working Groups
+
+The ESLint TSC may form working groups to focus on a specific area of the project.
+
+## Creating a Working Group
+
+Working groups are created by sending an email to the team mailing list. Each working group:
+
+1. Must have a GitHub team under the "ESLint Team" top-level GitHub team. (The GitHub team name should end with "WG" to distinguish it from other types of teams.)
+1. Must have at least one TSC member.
+1. May have any number of Committers and Reviewers.
+1. Must have at least two members.
+
+Active working groups are listed on the [team page](https://eslint.org/team).
+
+## How Working Groups Work
+
+Each working group is responsible for its own inner working. Working groups can decide how large or small they should be (so long as there is at least two members), when and who to add or remove from the working group, and how to accomplish their objectives.
+
+Working groups may be temporary or permanent.
+
+If working groups intend to make a significant change to the ESLint project, the proposal must still be approved by the TSC.
diff --git a/docs/rules/func-name-matching.md b/docs/rules/func-name-matching.md
index 870510290..53be2a099 100644
--- a/docs/rules/func-name-matching.md
+++ b/docs/rules/func-name-matching.md
@@ -91,7 +91,7 @@ This rule takes an optional string of "always" or "never" (when omitted, it defa
 
 ### considerPropertyDescriptor
 
-A boolean value that defaults to `false`. If `considerPropertyDescriptor` is set to true, the check will take into account the use `Object.create`, `Object.defineProperty`, `Object.defineProperties`, and `Reflect.defineProperty`.
+A boolean value that defaults to `false`. If `considerPropertyDescriptor` is set to true, the check will take into account the use of `Object.create`, `Object.defineProperty`, `Object.defineProperties`, and `Reflect.defineProperty`.
 
 Examples of **correct** code for the `{ considerPropertyDescriptor: true }` option:
 
diff --git a/docs/rules/no-restricted-modules.md b/docs/rules/no-restricted-modules.md
index 78ce092ba..7f9c926a1 100644
--- a/docs/rules/no-restricted-modules.md
+++ b/docs/rules/no-restricted-modules.md
@@ -35,10 +35,10 @@ It can also take an object with lists of `paths` and gitignore-style `patterns`
 You may also specify a custom message for any paths you want to restrict as follows:
 
 ```json
-"no-restricted-modules": ["error", [{
+"no-restricted-modules": ["error", {
   "name": "foo-module",
   "message": "Please use bar-module instead."
-  }]
+  }
 ]
 ```
 
diff --git a/docs/rules/prefer-named-capture-group.md b/docs/rules/prefer-named-capture-group.md
new file mode 100644
index 000000000..ff8790c83
--- /dev/null
+++ b/docs/rules/prefer-named-capture-group.md
@@ -0,0 +1,43 @@
+# Suggest using named capture group in regular expression (prefer-named-capture-group)
+
+With the landing of ECMAScript 2018, named capture groups can be used in regular expressions, which can improve their readability.
+
+```js
+const regex = /(?<year>[0-9]{4})/;
+```
+
+## Rule Details
+
+This rule is aimed at using named capture groups instead of numbered capture groups in regular expressions.
+
+Examples of **incorrect** code for this rule:
+
+```js
+/*eslint prefer-named-capture-group: "error"*/
+
+const foo = /(ba[rz])/;
+const bar = new RegExp('(ba[rz])');
+const baz = RegExp('(ba[rz])');
+
+foo.exec('bar')[1]; // Retrieve the group result.
+```
+
+Examples of **correct** code for this rule:
+
+```js
+/*eslint prefer-named-capture-group: "error"*/
+
+const foo = /(?<id>ba[rz])/;
+const bar = new RegExp('(?<id>ba[rz])');
+const baz = RegExp('(?<id>ba[rz])');
+
+foo.exec('bar').groups.id; // Retrieve the group result.
+```
+
+## When Not To Use It
+
+If you are targeting ECMAScript 2017 and/or older environments, you can disable this rule, because this ECMAScript feature is only supported in ECMAScript 2018 and/or newer environments.
+
+## Related Rules
+
+* [no-invalid-regexp](./no-invalid-regexp.md)
diff --git a/docs/user-guide/configuring.md b/docs/user-guide/configuring.md
index 87906837c..ec91ed774 100644
--- a/docs/user-guide/configuring.md
+++ b/docs/user-guide/configuring.md
@@ -23,7 +23,7 @@ Please note that supporting JSX syntax is not the same as supporting React. Reac
 By the same token, supporting ES6 syntax is not the same as supporting new ES6 globals (e.g., new types such as
 `Set`).
 For ES6 syntax, use `{ "parserOptions": { "ecmaVersion": 6 } }`; for new ES6 global variables, use `{ "env":
-{ "es6": true } }`. `{ env: { es6: true } }` enables ES6 syntax automatically, but `{ parserOptions: { ecmaVersion: 6 } }` does not enable ES6 globals automatically.
+{ "es6": true } }`. `{ "env": { "es6": true } }` enables ES6 syntax automatically, but `{ "parserOptions": { "ecmaVersion": 6 } }` does not enable ES6 globals automatically.
 Parser options are set in your `.eslintrc.*` file by using the `parserOptions` property. The available options are:
 
 * `ecmaVersion` - set to 3, 5 (default), 6, 7, 8, 9, or 10 to specify the version of ECMAScript syntax you want to use. You can also set to 2015 (same as 6), 2016 (same as 7), 2017 (same as 8), 2018 (same as 9), or 2019 (same as 10) to use the year-based naming.
diff --git a/lib/built-in-rules-index.js b/lib/built-in-rules-index.js
index aaf2f06ec..d75fbbc69 100644
--- a/lib/built-in-rules-index.js
+++ b/lib/built-in-rules-index.js
@@ -232,6 +232,7 @@ module.exports = {
     "prefer-arrow-callback": require("./rules/prefer-arrow-callback"),
     "prefer-const": require("./rules/prefer-const"),
     "prefer-destructuring": require("./rules/prefer-destructuring"),
+    "prefer-named-capture-group": require("./rules/prefer-named-capture-group"),
     "prefer-numeric-literals": require("./rules/prefer-numeric-literals"),
     "prefer-object-spread": require("./rules/prefer-object-spread"),
     "prefer-promise-reject-errors": require("./rules/prefer-promise-reject-errors"),
diff --git a/lib/config/config-file.js b/lib/config/config-file.js
index 492800b7a..80344f509 100644
--- a/lib/config/config-file.js
+++ b/lib/config/config-file.js
@@ -541,7 +541,7 @@ function loadFromDisk(resolvedPath, configContext) {
         const ruleMap = configContext.linterContext.getRules();
 
         // validate the configuration before continuing
-        validator.validate(config, resolvedPath.configFullName, ruleMap.get.bind(ruleMap), configContext.linterContext.environments);
+        validator.validate(config, ruleMap.get.bind(ruleMap), configContext.linterContext.environments, resolvedPath.configFullName);
 
         /*
          * If an `extends` property is defined, it represents a configuration file to use as
diff --git a/lib/config/config-validator.js b/lib/config/config-validator.js
index 2345b2889..386db7775 100644
--- a/lib/config/config-validator.js
+++ b/lib/config/config-validator.js
@@ -116,7 +116,7 @@ function validateRuleSchema(rule, localOptions) {
  * no source is prepended to the message.
  * @returns {void}
  */
-function validateRuleOptions(rule, ruleId, options, source) {
+function validateRuleOptions(rule, ruleId, options, source = null) {
     if (!rule) {
         return;
     }
@@ -140,11 +140,11 @@ function validateRuleOptions(rule, ruleId, options, source) {
 /**
  * Validates an environment object
  * @param {Object} environment The environment config object to validate.
- * @param {string} source The name of the configuration source to report in any errors.
  * @param {Environments} envContext Env context
+ * @param {string} source The name of the configuration source to report in any errors.
  * @returns {void}
  */
-function validateEnvironment(environment, source, envContext) {
+function validateEnvironment(environment, envContext, source = null) {
 
     // not having an environment is ok
     if (!environment) {
@@ -163,11 +163,11 @@ function validateEnvironment(environment, source, envContext) {
 /**
  * Validates a rules config object
  * @param {Object} rulesConfig The rules config object to validate.
- * @param {string} source The name of the configuration source to report in any errors.
  * @param {function(string): {create: Function}} ruleMapper A mapper function from strings to loaded rules
+ * @param {string} source The name of the configuration source to report in any errors.
  * @returns {void}
  */
-function validateRules(rulesConfig, source, ruleMapper) {
+function validateRules(rulesConfig, ruleMapper, source = null) {
     if (!rulesConfig) {
         return;
     }
@@ -228,7 +228,7 @@ const emitDeprecationWarning = lodash.memoize((source, errorCode) => {
  * @param {string} source The name of the configuration source to report in any errors.
  * @returns {void}
  */
-function validateConfigSchema(config, source) {
+function validateConfigSchema(config, source = null) {
     validateSchema = validateSchema || ajv.compile(configSchema);
 
     if (!validateSchema(config)) {
@@ -252,19 +252,19 @@ function validateConfigSchema(config, source) {
 /**
  * Validates an entire config object.
  * @param {Object} config The config object to validate.
- * @param {string} source The name of the configuration source to report in any errors.
  * @param {function(string): {create: Function}} ruleMapper A mapper function from rule IDs to defined rules
  * @param {Environments} envContext The env context
+ * @param {string} source The name of the configuration source to report in any errors.
  * @returns {void}
  */
-function validate(config, source, ruleMapper, envContext) {
+function validate(config, ruleMapper, envContext, source = null) {
     validateConfigSchema(config, source);
-    validateRules(config.rules, source, ruleMapper);
-    validateEnvironment(config.env, source, envContext);
+    validateRules(config.rules, ruleMapper, source);
+    validateEnvironment(config.env, envContext, source);
 
     for (const override of config.overrides || []) {
-        validateRules(override.rules, source, ruleMapper);
-        validateEnvironment(override.env, source, envContext);
+        validateRules(override.rules, ruleMapper, source);
+        validateEnvironment(override.env, envContext, source);
     }
 }
 
diff --git a/lib/rules/array-bracket-newline.js b/lib/rules/array-bracket-newline.js
index b98fa9d27..a458e69f7 100644
--- a/lib/rules/array-bracket-newline.js
+++ b/lib/rules/array-bracket-newline.js
@@ -34,13 +34,11 @@ module.exports = {
                         type: "object",
                         properties: {
                             multiline: {
-                                type: "boolean",
-                                default: true
+                                type: "boolean"
                             },
                             minItems: {
                                 type: ["integer", "null"],
-                                minimum: 0,
-                                default: null
+                                minimum: 0
                             }
                         },
                         additionalProperties: false
diff --git a/lib/rules/array-element-newline.js b/lib/rules/array-element-newline.js
index 0efceedd2..dadb26fdd 100644
--- a/lib/rules/array-element-newline.js
+++ b/lib/rules/array-element-newline.js
@@ -34,13 +34,11 @@ module.exports = {
                         type: "object",
                         properties: {
                             multiline: {
-                                type: "boolean",
-                                default: false
+                                type: "boolean"
                             },
                             minItems: {
                                 type: ["integer", "null"],
-                                minimum: 0,
-                                default: null
+                                minimum: 0
                             }
                         },
                         additionalProperties: false
diff --git a/lib/rules/arrow-body-style.js b/lib/rules/arrow-body-style.js
index 28001d7f4..b1fed8c15 100644
--- a/lib/rules/arrow-body-style.js
+++ b/lib/rules/arrow-body-style.js
@@ -46,7 +46,7 @@ module.exports = {
                         {
                             type: "object",
                             properties: {
-                                requireReturnForObjectLiteral: { type: "boolean", default: false }
+                                requireReturnForObjectLiteral: { type: "boolean" }
                             },
                             additionalProperties: false
                         }
diff --git a/lib/rules/capitalized-comments.js b/lib/rules/capitalized-comments.js
index a488eb20b..137be9e93 100644
--- a/lib/rules/capitalized-comments.js
+++ b/lib/rules/capitalized-comments.js
@@ -28,27 +28,22 @@ const SCHEMA_BODY = {
     type: "object",
     properties: {
         ignorePattern: {
-            type: "string",
-            default: ""
+            type: "string"
         },
         ignoreInlineComments: {
-            type: "boolean",
-            default: false
+            type: "boolean"
         },
         ignoreConsecutiveComments: {
-            type: "boolean",
-            default: false
+            type: "boolean"
         }
     },
     additionalProperties: false
 };
-const DEFAULTS = Object.keys(SCHEMA_BODY.properties).reduce(
-    (obj, current) => {
-        obj[current] = SCHEMA_BODY.properties[current].default;
-        return obj;
-    },
-    {}
-);
+const DEFAULTS = {
+    ignorePattern: "",
+    ignoreInlineComments: false,
+    ignoreConsecutiveComments: false
+};
 
 /**
  * Get normalized options for either block or line comments from the given
diff --git a/lib/rules/complexity.js b/lib/rules/complexity.js
index 9f791e6de..56e17ddf2 100644
--- a/lib/rules/complexity.js
+++ b/lib/rules/complexity.js
@@ -41,13 +41,11 @@ module.exports = {
                         properties: {
                             maximum: {
                                 type: "integer",
-                                minimum: 0,
-                                default: 20
+                                minimum: 0
                             },
                             max: {
                                 type: "integer",
-                                minimum: 0,
-                                default: 20
+                                minimum: 0
                             }
                         },
                         additionalProperties: false
@@ -65,7 +63,10 @@ module.exports = {
         const option = context.options[0];
         let THRESHOLD = 20;
 
-        if (typeof option === "object") {
+        if (
+            typeof option === "object" &&
+            (Object.prototype.hasOwnProperty.call(option, "maximum") || Object.prototype.hasOwnProperty.call(option, "max"))
+        ) {
             THRESHOLD = option.maximum || option.max;
         } else if (typeof option === "number") {
             THRESHOLD = option;
diff --git a/lib/rules/eqeqeq.js b/lib/rules/eqeqeq.js
index a52de67d7..3e8a392cf 100644
--- a/lib/rules/eqeqeq.js
+++ b/lib/rules/eqeqeq.js
@@ -38,8 +38,7 @@ module.exports = {
                             type: "object",
                             properties: {
                                 null: {
-                                    enum: ["always", "never", "ignore"],
-                                    default: "always"
+                                    enum: ["always", "never", "ignore"]
                                 }
                             },
                             additionalProperties: false
diff --git a/lib/rules/func-call-spacing.js b/lib/rules/func-call-spacing.js
index 348f5a8f4..223756851 100644
--- a/lib/rules/func-call-spacing.js
+++ b/lib/rules/func-call-spacing.js
@@ -50,8 +50,7 @@ module.exports = {
                             type: "object",
                             properties: {
                                 allowNewlines: {
-                                    type: "boolean",
-                                    default: false
+                                    type: "boolean"
                                 }
                             },
                             additionalProperties: false
diff --git a/lib/rules/init-declarations.js b/lib/rules/init-declarations.js
index 484cbef0a..65197358e 100644
--- a/lib/rules/init-declarations.js
+++ b/lib/rules/init-declarations.js
@@ -75,8 +75,7 @@ module.exports = {
                             type: "object",
                             properties: {
                                 ignoreForLoopInit: {
-                                    type: "boolean",
-                                    default: false
+                                    type: "boolean"
                                 }
                             },
                             additionalProperties: false
diff --git a/lib/rules/key-spacing.js b/lib/rules/key-spacing.js
index 3f4d711c1..7da7f9aa0 100644
--- a/lib/rules/key-spacing.js
+++ b/lib/rules/key-spacing.js
@@ -148,20 +148,16 @@ module.exports = {
                                     type: "object",
                                     properties: {
                                         mode: {
-                                            enum: ["strict", "minimum"],
-                                            default: "strict"
+                                            enum: ["strict", "minimum"]
                                         },
                                         on: {
-                                            enum: ["colon", "value"],
-                                            default: "colon"
+                                            enum: ["colon", "value"]
                                         },
                                         beforeColon: {
-                                            type: "boolean",
-                                            default: false
+                                            type: "boolean"
                                         },
                                         afterColon: {
-                                            type: "boolean",
-                                            default: true
+                                            type: "boolean"
                                         }
                                     },
                                     additionalProperties: false
@@ -169,16 +165,13 @@ module.exports = {
                             ]
                         },
                         mode: {
-                            enum: ["strict", "minimum"],
-                            default: "strict"
+                            enum: ["strict", "minimum"]
                         },
                         beforeColon: {
-                            type: "boolean",
-                            default: false
+                            type: "boolean"
                         },
                         afterColon: {
-                            type: "boolean",
-                            default: true
+                            type: "boolean"
                         }
                     },
                     additionalProperties: false
@@ -190,16 +183,13 @@ module.exports = {
                             type: "object",
                             properties: {
                                 mode: {
-                                    enum: ["strict", "minimum"],
-                                    default: "strict"
+                                    enum: ["strict", "minimum"]
                                 },
                                 beforeColon: {
-                                    type: "boolean",
-                                    default: false
+                                    type: "boolean"
                                 },
                                 afterColon: {
-                                    type: "boolean",
-                                    default: true
+                                    type: "boolean"
                                 }
                             },
                             additionalProperties: false
@@ -216,20 +206,16 @@ module.exports = {
                                             type: "object",
                                             properties: {
                                                 mode: {
-                                                    enum: ["strict", "minimum"],
-                                                    default: "strict"
+                                                    enum: ["strict", "minimum"]
                                                 },
                                                 on: {
-                                                    enum: ["colon", "value"],
-                                                    default: "colon"
+                                                    enum: ["colon", "value"]
                                                 },
                                                 beforeColon: {
-                                                    type: "boolean",
-                                                    default: false
+                                                    type: "boolean"
                                                 },
                                                 afterColon: {
-                                                    type: "boolean",
-                                                    default: true
+                                                    type: "boolean"
                                                 }
                                             },
                                             additionalProperties: false
@@ -237,16 +223,13 @@ module.exports = {
                                     ]
                                 },
                                 mode: {
-                                    enum: ["strict", "minimum"],
-                                    default: "strict"
+                                    enum: ["strict", "minimum"]
                                 },
                                 beforeColon: {
-                                    type: "boolean",
-                                    default: false
+                                    type: "boolean"
                                 },
                                 afterColon: {
-                                    type: "boolean",
-                                    default: true
+                                    type: "boolean"
                                 }
                             },
                             additionalProperties: false
@@ -261,16 +244,13 @@ module.exports = {
                             type: "object",
                             properties: {
                                 mode: {
-                                    enum: ["strict", "minimum"],
-                                    default: "strict"
+                                    enum: ["strict", "minimum"]
                                 },
                                 beforeColon: {
-                                    type: "boolean",
-                                    default: false
+                                    type: "boolean"
                                 },
                                 afterColon: {
-                                    type: "boolean",
-                                    default: true
+                                    type: "boolean"
                                 }
                             },
                             additionalProperties: false
@@ -279,16 +259,13 @@ module.exports = {
                             type: "object",
                             properties: {
                                 mode: {
-                                    enum: ["strict", "minimum"],
-                                    default: "strict"
+                                    enum: ["strict", "minimum"]
                                 },
                                 beforeColon: {
-                                    type: "boolean",
-                                    default: false
+                                    type: "boolean"
                                 },
                                 afterColon: {
-                                    type: "boolean",
-                                    default: true
+                                    type: "boolean"
                                 }
                             },
                             additionalProperties: false
@@ -297,20 +274,16 @@ module.exports = {
                             type: "object",
                             properties: {
                                 mode: {
-                                    enum: ["strict", "minimum"],
-                                    default: "strict"
+                                    enum: ["strict", "minimum"]
                                 },
                                 on: {
-                                    enum: ["colon", "value"],
-                                    default: "colon"
+                                    enum: ["colon", "value"]
                                 },
                                 beforeColon: {
-                                    type: "boolean",
-                                    default: false
+                                    type: "boolean"
                                 },
                                 afterColon: {
-                                    type: "boolean",
-                                    default: true
+                                    type: "boolean"
                                 }
                             },
                             additionalProperties: false
diff --git a/lib/rules/line-comment-position.js b/lib/rules/line-comment-position.js
index 21f1127af..0023a1f11 100644
--- a/lib/rules/line-comment-position.js
+++ b/lib/rules/line-comment-position.js
@@ -38,12 +38,10 @@ module.exports = {
                                 type: "string"
                             },
                             applyDefaultPatterns: {
-                                type: "boolean",
-                                default: true
+                                type: "boolean"
                             },
                             applyDefaultIgnorePatterns: {
-                                type: "boolean",
-                                default: true
+                                type: "boolean"
                             }
                         },
                         additionalProperties: false
@@ -74,7 +72,7 @@ module.exports = {
             if (Object.prototype.hasOwnProperty.call(options, "applyDefaultIgnorePatterns")) {
                 applyDefaultIgnorePatterns = options.applyDefaultIgnorePatterns;
             } else {
-                applyDefaultIgnorePatterns = options.applyDefaultPatterns;
+                applyDefaultIgnorePatterns = options.applyDefaultPatterns !== false;
             }
         }
 
diff --git a/lib/rules/max-depth.js b/lib/rules/max-depth.js
index 3b997e21b..de684dd92 100644
--- a/lib/rules/max-depth.js
+++ b/lib/rules/max-depth.js
@@ -32,13 +32,11 @@ module.exports = {
                         properties: {
                             maximum: {
                                 type: "integer",
-                                minimum: 0,
-                                default: 4
+                                minimum: 0
                             },
                             max: {
                                 type: "integer",
-                                minimum: 0,
-                                default: 4
+                                minimum: 0
                             }
                         },
                         additionalProperties: false
@@ -61,7 +59,10 @@ module.exports = {
             option = context.options[0];
         let maxDepth = 4;
 
-        if (typeof option === "object") {
+        if (
+            typeof option === "object" &&
+            (Object.prototype.hasOwnProperty.call(option, "maximum") || Object.prototype.hasOwnProperty.call(option, "max"))
+        ) {
             maxDepth = option.maximum || option.max;
         }
         if (typeof option === "number") {
diff --git a/lib/rules/max-lines.js b/lib/rules/max-lines.js
index 0fae4ec2f..4e5f23b5d 100644
--- a/lib/rules/max-lines.js
+++ b/lib/rules/max-lines.js
@@ -38,16 +38,13 @@ module.exports = {
                         properties: {
                             max: {
                                 type: "integer",
-                                minimum: 0,
-                                default: 300
+                                minimum: 0
                             },
                             skipComments: {
-                                type: "boolean",
-                                default: false
+                                type: "boolean"
                             },
                             skipBlankLines: {
-                                type: "boolean",
-                                default: false
+                                type: "boolean"
                             }
                         },
                         additionalProperties: false
@@ -64,7 +61,7 @@ module.exports = {
         const option = context.options[0];
         let max = 300;
 
-        if (typeof option === "object") {
+        if (typeof option === "object" && Object.prototype.hasOwnProperty.call(option, "max")) {
             max = option.max;
         } else if (typeof option === "number") {
             max = option;
diff --git a/lib/rules/max-nested-callbacks.js b/lib/rules/max-nested-callbacks.js
index cbbb0ed6c..df1baceeb 100644
--- a/lib/rules/max-nested-callbacks.js
+++ b/lib/rules/max-nested-callbacks.js
@@ -32,13 +32,11 @@ module.exports = {
                         properties: {
                             maximum: {
                                 type: "integer",
-                                minimum: 0,
-                                default: 10
+                                minimum: 0
                             },
                             max: {
                                 type: "integer",
-                                minimum: 0,
-                                default: 10
+                                minimum: 0
                             }
                         },
                         additionalProperties: false
@@ -59,7 +57,10 @@ module.exports = {
         const option = context.options[0];
         let THRESHOLD = 10;
 
-        if (typeof option === "object") {
+        if (
+            typeof option === "object" &&
+            (Object.prototype.hasOwnProperty.call(option, "maximum") || Object.prototype.hasOwnProperty.call(option, "max"))
+        ) {
             THRESHOLD = option.maximum || option.max;
         } else if (typeof option === "number") {
             THRESHOLD = option;
diff --git a/lib/rules/max-params.js b/lib/rules/max-params.js
index 5e1e558ab..e1de3ef6f 100644
--- a/lib/rules/max-params.js
+++ b/lib/rules/max-params.js
@@ -40,13 +40,11 @@ module.exports = {
                         properties: {
                             maximum: {
                                 type: "integer",
-                                minimum: 0,
-                                default: 3
+                                minimum: 0
                             },
                             max: {
                                 type: "integer",
-                                minimum: 0,
-                                default: 3
+                                minimum: 0
                             }
                         },
                         additionalProperties: false
@@ -64,7 +62,10 @@ module.exports = {
         const option = context.options[0];
         let numParams = 3;
 
-        if (typeof option === "object") {
+        if (
+            typeof option === "object" &&
+            (Object.prototype.hasOwnProperty.call(option, "maximum") || Object.prototype.hasOwnProperty.call(option, "max"))
+        ) {
             numParams = option.maximum || option.max;
         }
         if (typeof option === "number") {
diff --git a/lib/rules/max-statements.js b/lib/rules/max-statements.js
index cd0e50ae3..7dc3fd50c 100644
--- a/lib/rules/max-statements.js
+++ b/lib/rules/max-statements.js
@@ -40,13 +40,11 @@ module.exports = {
                         properties: {
                             maximum: {
                                 type: "integer",
-                                minimum: 0,
-                                default: 10
+                                minimum: 0
                             },
                             max: {
                                 type: "integer",
-                                minimum: 0,
-                                default: 10
+                                minimum: 0
                             }
                         },
                         additionalProperties: false
@@ -80,7 +78,10 @@ module.exports = {
             topLevelFunctions = [];
         let maxStatements = 10;
 
-        if (typeof option === "object") {
+        if (
+            typeof option === "object" &&
+            (Object.prototype.hasOwnProperty.call(option, "maximum") || Object.prototype.hasOwnProperty.call(option, "max"))
+        ) {
             maxStatements = option.maximum || option.max;
         } else if (typeof option === "number") {
             maxStatements = option;
diff --git a/lib/rules/no-extra-parens.js b/lib/rules/no-extra-parens.js
index 9f16e0e6c..400ce0c76 100644
--- a/lib/rules/no-extra-parens.js
+++ b/lib/rules/no-extra-parens.js
@@ -44,11 +44,11 @@ module.exports = {
                         {
                             type: "object",
                             properties: {
-                                conditionalAssign: { type: "boolean", default: true },
-                                nestedBinaryExpressions: { type: "boolean", default: true },
-                                returnAssign: { type: "boolean", default: true },
+                                conditionalAssign: { type: "boolean" },
+                                nestedBinaryExpressions: { type: "boolean" },
+                                returnAssign: { type: "boolean" },
                                 ignoreJSX: { enum: ["none", "all", "single-line", "multi-line"] },
-                                enforceForArrowConditionals: { type: "boolean", default: true }
+                                enforceForArrowConditionals: { type: "boolean" }
                             },
                             additionalProperties: false
                         }
@@ -471,6 +471,7 @@ module.exports = {
             const firstToken = isParenthesised(node) ? sourceCode.getTokenBefore(node) : sourceCode.getFirstToken(node);
             const secondToken = sourceCode.getTokenAfter(firstToken, astUtils.isNotOpeningParenToken);
             const thirdToken = secondToken ? sourceCode.getTokenAfter(secondToken) : null;
+            const tokenAfterClosingParens = secondToken ? sourceCode.getTokenAfter(secondToken, astUtils.isNotClosingParenToken) : null;
 
             if (
                 astUtils.isOpeningParenToken(firstToken) &&
@@ -479,7 +480,12 @@ module.exports = {
                     secondToken.type === "Keyword" && (
                         secondToken.value === "function" ||
                         secondToken.value === "class" ||
-                        secondToken.value === "let" && astUtils.isOpeningBracketToken(sourceCode.getTokenAfter(secondToken, astUtils.isNotClosingParenToken))
+                        secondToken.value === "let" &&
+                            tokenAfterClosingParens &&
+                            (
+                                astUtils.isOpeningBracketToken(tokenAfterClosingParens) ||
+                                tokenAfterClosingParens.type === "Identifier"
+                            )
                     ) ||
                     secondToken && secondToken.type === "Identifier" && secondToken.value === "async" && thirdToken && thirdToken.type === "Keyword" && thirdToken.value === "function"
                 )
diff --git a/lib/rules/no-mixed-requires.js b/lib/rules/no-mixed-requires.js
index e79dde0fe..e3164a8ab 100644
--- a/lib/rules/no-mixed-requires.js
+++ b/lib/rules/no-mixed-requires.js
@@ -30,12 +30,10 @@ module.exports = {
                         type: "object",
                         properties: {
                             grouping: {
-                                type: "boolean",
-                                default: false
+                                type: "boolean"
                             },
                             allowCall: {
-                                type: "boolean",
-                                default: false
+                                type: "boolean"
                             }
                         },
                         additionalProperties: false
diff --git a/lib/rules/no-unused-vars.js b/lib/rules/no-unused-vars.js
index de13f26ce..d4c4c6355 100644
--- a/lib/rules/no-unused-vars.js
+++ b/lib/rules/no-unused-vars.js
@@ -37,26 +37,22 @@ module.exports = {
                         type: "object",
                         properties: {
                             vars: {
-                                enum: ["all", "local"],
-                                default: "all"
+                                enum: ["all", "local"]
                             },
                             varsIgnorePattern: {
                                 type: "string"
                             },
                             args: {
-                                enum: ["all", "after-used", "none"],
-                                default: "after-used"
+                                enum: ["all", "after-used", "none"]
                             },
                             ignoreRestSiblings: {
-                                type: "boolean",
-                                default: false
+                                type: "boolean"
                             },
                             argsIgnorePattern: {
                                 type: "string"
                             },
                             caughtErrors: {
-                                enum: ["all", "none"],
-                                default: "none"
+                                enum: ["all", "none"]
                             },
                             caughtErrorsIgnorePattern: {
                                 type: "string"
diff --git a/lib/rules/no-use-before-define.js b/lib/rules/no-use-before-define.js
index 61998c7a8..a98f6c87f 100644
--- a/lib/rules/no-use-before-define.js
+++ b/lib/rules/no-use-before-define.js
@@ -154,9 +154,9 @@ module.exports = {
                     {
                         type: "object",
                         properties: {
-                            functions: { type: "boolean", default: true },
-                            classes: { type: "boolean", default: true },
-                            variables: { type: "boolean", default: true }
+                            functions: { type: "boolean" },
+                            classes: { type: "boolean" },
+                            variables: { type: "boolean" }
                         },
                         additionalProperties: false
                     }
diff --git a/lib/rules/no-warning-comments.js b/lib/rules/no-warning-comments.js
index 0dd0a26c1..1d1b55460 100644
--- a/lib/rules/no-warning-comments.js
+++ b/lib/rules/no-warning-comments.js
@@ -95,7 +95,7 @@ module.exports = {
                  * ^\s*TERM\b.  This checks the word boundary
                  * at the beginning of the comment.
                  */
-                return new RegExp(prefix + escaped + suffix, "iu");
+                return new RegExp(prefix + escaped + suffix, "i"); // eslint-disable-line require-unicode-regexp
             }
 
             /*
@@ -103,7 +103,7 @@ module.exports = {
              * \bTERM\b|\bTERM\b, this checks the entire comment
              * for the term.
              */
-            return new RegExp(prefix + escaped + suffix + eitherOrWordBoundary + term + wordBoundary, "iu");
+            return new RegExp(prefix + escaped + suffix + eitherOrWordBoundary + term + wordBoundary, "i"); // eslint-disable-line require-unicode-regexp
         }
 
         const warningRegExps = warningTerms.map(convertToRegExp);
diff --git a/lib/rules/object-curly-newline.js b/lib/rules/object-curly-newline.js
index d45620d53..d1a6bc20f 100644
--- a/lib/rules/object-curly-newline.js
+++ b/lib/rules/object-curly-newline.js
@@ -26,16 +26,14 @@ const OPTION_VALUE = {
             type: "object",
             properties: {
                 multiline: {
-                    type: "boolean",
-                    default: false
+                    type: "boolean"
                 },
                 minProperties: {
                     type: "integer",
                     minimum: 0
                 },
                 consistent: {
-                    type: "boolean",
-                    default: false
+                    type: "boolean"
                 }
             },
             additionalProperties: false,
@@ -61,9 +59,9 @@ function normalizeOptionValue(value) {
         } else if (value === "never") {
             minProperties = Number.POSITIVE_INFINITY;
         } else {
-            multiline = value.multiline;
+            multiline = Boolean(value.multiline);
             minProperties = value.minProperties || Number.POSITIVE_INFINITY;
-            consistent = value.consistent;
+            consistent = Boolean(value.consistent);
         }
     } else {
         consistent = true;
diff --git a/lib/rules/object-shorthand.js b/lib/rules/object-shorthand.js
index 98917fb6e..31010f0e7 100644
--- a/lib/rules/object-shorthand.js
+++ b/lib/rules/object-shorthand.js
@@ -57,8 +57,7 @@ module.exports = {
                             type: "object",
                             properties: {
                                 avoidQuotes: {
-                                    type: "boolean",
-                                    default: false
+                                    type: "boolean"
                                 }
                             },
                             additionalProperties: false
@@ -77,16 +76,13 @@ module.exports = {
                             type: "object",
                             properties: {
                                 ignoreConstructors: {
-                                    type: "boolean",
-                                    default: false
+                                    type: "boolean"
                                 },
                                 avoidQuotes: {
-                                    type: "boolean",
-                                    default: false
+                                    type: "boolean"
                                 },
                                 avoidExplicitReturnArrows: {
-                                    type: "boolean",
-                                    default: false
+                                    type: "boolean"
                                 }
                             },
                             additionalProperties: false
diff --git a/lib/rules/one-var.js b/lib/rules/one-var.js
index 5a5c71b18..0571cd338 100644
--- a/lib/rules/one-var.js
+++ b/lib/rules/one-var.js
@@ -36,16 +36,13 @@ module.exports = {
                                 default: false
                             },
                             var: {
-                                enum: ["always", "never", "consecutive"],
-                                default: "always"
+                                enum: ["always", "never", "consecutive"]
                             },
                             let: {
-                                enum: ["always", "never", "consecutive"],
-                                default: "always"
+                                enum: ["always", "never", "consecutive"]
                             },
                             const: {
-                                enum: ["always", "never", "consecutive"],
-                                default: "always"
+                                enum: ["always", "never", "consecutive"]
                             }
                         },
                         additionalProperties: false
diff --git a/lib/rules/prefer-destructuring.js b/lib/rules/prefer-destructuring.js
index c30c9170c..dec93d51f 100644
--- a/lib/rules/prefer-destructuring.js
+++ b/lib/rules/prefer-destructuring.js
@@ -36,12 +36,10 @@ module.exports = {
                                 type: "object",
                                 properties: {
                                     array: {
-                                        type: "boolean",
-                                        default: true
+                                        type: "boolean"
                                     },
                                     object: {
-                                        type: "boolean",
-                                        default: true
+                                        type: "boolean"
                                     }
                                 },
                                 additionalProperties: false
@@ -50,12 +48,10 @@ module.exports = {
                                 type: "object",
                                 properties: {
                                     array: {
-                                        type: "boolean",
-                                        default: true
+                                        type: "boolean"
                                     },
                                     object: {
-                                        type: "boolean",
-                                        default: true
+                                        type: "boolean"
                                     }
                                 },
                                 additionalProperties: false
@@ -67,12 +63,10 @@ module.exports = {
                         type: "object",
                         properties: {
                             array: {
-                                type: "boolean",
-                                default: true
+                                type: "boolean"
                             },
                             object: {
-                                type: "boolean",
-                                default: true
+                                type: "boolean"
                             }
                         },
                         additionalProperties: false
@@ -83,8 +77,7 @@ module.exports = {
                 type: "object",
                 properties: {
                     enforceForRenamedProperties: {
-                        type: "boolean",
-                        default: false
+                        type: "boolean"
                     }
                 },
                 additionalProperties: false
diff --git a/lib/rules/prefer-named-capture-group.js b/lib/rules/prefer-named-capture-group.js
new file mode 100644
index 000000000..07e69f022
--- /dev/null
+++ b/lib/rules/prefer-named-capture-group.js
@@ -0,0 +1,123 @@
+/**
+ * @fileoverview Rule to enforce requiring named capture groups in regular expression.
+ * @author Pig Fang <https://github.com/g-plane>
+ */
+
+"use strict";
+
+//------------------------------------------------------------------------------
+// Requirements
+//------------------------------------------------------------------------------
+
+const {
+    CALL,
+    CONSTRUCT,
+    ReferenceTracker,
+    getStringIfConstant
+} = require("eslint-utils");
+const regexpp = require("regexpp");
+
+//------------------------------------------------------------------------------
+// Helpers
+//------------------------------------------------------------------------------
+
+const parser = new regexpp.RegExpParser();
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = {
+    meta: {
+        type: "suggestion",
+
+        docs: {
+            description: "enforce using named capture group in regular expression",
+            category: "Best Practices",
+            recommended: false,
+            url: "https://eslint.org/docs/rules/prefer-named-capture-group"
+        },
+
+        schema: [],
+
+        messages: {
+            required: "Capture group '{{group}}' should be converted to a named or non-capturing group."
+        }
+    },
+
+    create(context) {
+
+        /**
+         * Function to check regular expression.
+         *
+         * @param {string} regex The regular expression to be check.
+         * @param {ASTNode} node AST node which contains regular expression.
+         * @param {boolean} uFlag Flag indicates whether unicode mode is enabled or not.
+         * @returns {void}
+         */
+        function checkRegex(regex, node, uFlag) {
+            let ast;
+
+            try {
+                ast = parser.parsePattern(regex, 0, regex.length, uFlag);
+            } catch (_) {
+
+                // ignore regex syntax errors
+                return;
+            }
+
+            regexpp.visitRegExpAST(ast, {
+                onCapturingGroupEnter(group) {
+                    if (!group.name) {
+                        const locNode = node.type === "Literal" ? node : node.arguments[0];
+
+                        context.report({
+                            node,
+                            messageId: "required",
+                            loc: {
+                                start: {
+                                    line: locNode.loc.start.line,
+                                    column: locNode.loc.start.column + group.start + 1
+                                },
+                                end: {
+                                    line: locNode.loc.start.line,
+                                    column: locNode.loc.start.column + group.end + 1
+                                }
+                            },
+                            data: {
+                                group: group.raw
+                            }
+                        });
+                    }
+                }
+            });
+        }
+
+        return {
+            Literal(node) {
+                if (node.regex) {
+                    checkRegex(node.regex.pattern, node, node.regex.flags.includes("u"));
+                }
+            },
+            Program() {
+                const scope = context.getScope();
+                const tracker = new ReferenceTracker(scope);
+                const traceMap = {
+                    RegExp: {
+                        [CALL]: true,
+                        [CONSTRUCT]: true
+                    }
+                };
+
+                for (const { node } of tracker.iterateGlobalReferences(traceMap)) {
+                    const regex = getStringIfConstant(node.arguments[0]);
+                    const flags = getStringIfConstant(node.arguments[1]);
+
+                    if (regex) {
+                        checkRegex(regex, node, flags && flags.includes("u"));
+                    }
+                }
+            }
+        };
+    }
+};
diff --git a/lib/rules/quote-props.js b/lib/rules/quote-props.js
index f4582dd1f..7184bd34d 100644
--- a/lib/rules/quote-props.js
+++ b/lib/rules/quote-props.js
@@ -32,8 +32,7 @@ module.exports = {
                     type: "array",
                     items: [
                         {
-                            enum: ["always", "as-needed", "consistent", "consistent-as-needed"],
-                            default: "always"
+                            enum: ["always", "as-needed", "consistent", "consistent-as-needed"]
                         }
                     ],
                     minItems: 0,
@@ -43,23 +42,19 @@ module.exports = {
                     type: "array",
                     items: [
                         {
-                            enum: ["always", "as-needed", "consistent", "consistent-as-needed"],
-                            default: "always"
+                            enum: ["always", "as-needed", "consistent", "consistent-as-needed"]
                         },
                         {
                             type: "object",
                             properties: {
                                 keywords: {
-                                    type: "boolean",
-                                    default: false
+                                    type: "boolean"
                                 },
                                 unnecessary: {
-                                    type: "boolean",
-                                    default: true
+                                    type: "boolean"
                                 },
                                 numbers: {
-                                    type: "boolean",
-                                    default: false
+                                    type: "boolean"
                                 }
                             },
                             additionalProperties: false
diff --git a/lib/rules/quotes.js b/lib/rules/quotes.js
index 887a0b75f..4556b245d 100644
--- a/lib/rules/quotes.js
+++ b/lib/rules/quotes.js
@@ -100,12 +100,10 @@ module.exports = {
                         type: "object",
                         properties: {
                             avoidEscape: {
-                                type: "boolean",
-                                default: false
+                                type: "boolean"
                             },
                             allowTemplateLiterals: {
-                                type: "boolean",
-                                default: false
+                                type: "boolean"
                             }
                         },
                         additionalProperties: false
diff --git a/lib/rules/semi.js b/lib/rules/semi.js
index 740ce53f4..3a6df39c7 100644
--- a/lib/rules/semi.js
+++ b/lib/rules/semi.js
@@ -40,8 +40,7 @@ module.exports = {
                             type: "object",
                             properties: {
                                 beforeStatementContinuationChars: {
-                                    enum: ["always", "any", "never"],
-                                    default: "any"
+                                    enum: ["always", "any", "never"]
                                 }
                             },
                             additionalProperties: false
@@ -59,7 +58,7 @@ module.exports = {
                         {
                             type: "object",
                             properties: {
-                                omitLastInOneLineBlock: { type: "boolean", default: false }
+                                omitLastInOneLineBlock: { type: "boolean" }
                             },
                             additionalProperties: false
                         }
@@ -76,8 +75,8 @@ module.exports = {
         const OPT_OUT_PATTERN = /^[-[(/+`]/u; // One of [(/+-`
         const options = context.options[1];
         const never = context.options[0] === "never";
-        const exceptOneLine = options && options.omitLastInOneLineBlock;
-        const beforeStatementContinuationChars = options && options.beforeStatementContinuationChars;
+        const exceptOneLine = Boolean(options && options.omitLastInOneLineBlock);
+        const beforeStatementContinuationChars = options && options.beforeStatementContinuationChars || "any";
         const sourceCode = context.getSourceCode();
 
         //--------------------------------------------------------------------------
diff --git a/lib/rules/space-before-function-paren.js b/lib/rules/space-before-function-paren.js
index c0d8e509f..64ba72bf9 100644
--- a/lib/rules/space-before-function-paren.js
+++ b/lib/rules/space-before-function-paren.js
@@ -37,16 +37,13 @@ module.exports = {
                         type: "object",
                         properties: {
                             anonymous: {
-                                enum: ["always", "never", "ignore"],
-                                default: "always"
+                                enum: ["always", "never", "ignore"]
                             },
                             named: {
-                                enum: ["always", "never", "ignore"],
-                                default: "always"
+                                enum: ["always", "never", "ignore"]
                             },
                             asyncArrow: {
-                                enum: ["always", "never", "ignore"],
-                                default: "always"
+                                enum: ["always", "never", "ignore"]
                             }
                         },
                         additionalProperties: false
diff --git a/lib/rules/yield-star-spacing.js b/lib/rules/yield-star-spacing.js
index 17124dd6e..20b8e9ea9 100644
--- a/lib/rules/yield-star-spacing.js
+++ b/lib/rules/yield-star-spacing.js
@@ -31,8 +31,8 @@ module.exports = {
                     {
                         type: "object",
                         properties: {
-                            before: { type: "boolean", default: false },
-                            after: { type: "boolean", default: true }
+                            before: { type: "boolean" },
+                            after: { type: "boolean" }
                         },
                         additionalProperties: false
                     }
diff --git a/package.json b/package.json
index 5fea28537..2d9f0d0be 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "eslint",
-  "version": "5.14.1",
+  "version": "5.15.1",
   "author": "Nicholas C. Zakas <nicholas+npm@nczconsulting.com>",
   "description": "An AST-based pattern checker for JavaScript.",
   "bin": {
@@ -41,7 +41,7 @@
     "cross-spawn": "^6.0.5",
     "debug": "^4.0.1",
     "doctrine": "^3.0.0",
-    "eslint-scope": "^4.0.0",
+    "eslint-scope": "^4.0.2",
     "eslint-utils": "^1.3.1",
     "eslint-visitor-keys": "^1.0.0",
     "espree": "^5.0.1",
@@ -85,11 +85,11 @@
     "coveralls": "^3.0.1",
     "dateformat": "^3.0.3",
     "ejs": "^2.6.1",
+    "eslint-config-eslint": "file:packages/eslint-config-eslint",
     "eslint-plugin-eslint-plugin": "^2.0.1",
+    "eslint-plugin-internal-rules": "file:tools/internal-rules",
     "eslint-plugin-node": "^8.0.0",
-    "eslint-plugin-rulesdir": "^0.1.0",
     "eslint-release": "^1.2.0",
-    "eslint-rule-composer": "^0.3.0",
     "eslump": "^2.0.0",
     "esprima": "^4.0.1",
     "istanbul": "^0.4.5",
diff --git a/packages/eslint-config-eslint/default.yml b/packages/eslint-config-eslint/default.yml
index 0cfe3506b..cad812907 100644
--- a/packages/eslint-config-eslint/default.yml
+++ b/packages/eslint-config-eslint/default.yml
@@ -13,7 +13,7 @@ rules:
     camelcase: "error"
     callback-return: ["error", ["cb", "callback", "next"]]
     class-methods-use-this: "error"
-    comma-dangle: "error"
+    comma-dangle: ["error", { functions: "never" }]
     comma-spacing: "error"
     comma-style: ["error", "last"]
     computed-property-spacing: "error"
diff --git a/tools/internal-rules/index.js b/tools/internal-rules/index.js
new file mode 100644
index 000000000..a3a3cd199
--- /dev/null
+++ b/tools/internal-rules/index.js
@@ -0,0 +1,13 @@
+"use strict";
+
+const fs = require("fs");
+const path = require("path");
+
+module.exports = {
+    rules: Object.assign(
+        {},
+        ...fs.readdirSync(__dirname)
+            .filter(filename => filename.endsWith(".js") && filename !== "index.js")
+            .map(filename => ({ [filename.replace(/\.js$/u, "")]: require(path.resolve(__dirname, filename)) }))
+    )
+};
diff --git a/tools/internal-rules/multiline-comment-style.js b/tools/internal-rules/multiline-comment-style.js
index f0d5755e8..b0a0c9d85 100644
--- a/tools/internal-rules/multiline-comment-style.js
+++ b/tools/internal-rules/multiline-comment-style.js
@@ -13,7 +13,7 @@ const multilineCommentStyle = require("../../lib/rules/multiline-comment-style")
 //------------------------------------------------------------------------------
 
 // The `no-invalid-meta` internal rule has a false positive here.
-// eslint-disable-next-line rulesdir/no-invalid-meta
+// eslint-disable-next-line internal-rules/no-invalid-meta
 module.exports = ruleComposer.filterReports(
     multilineCommentStyle,
     (problem, metadata) => {
diff --git a/tools/internal-rules/package.json b/tools/internal-rules/package.json
new file mode 100644
index 000000000..0d80ed277
--- /dev/null
+++ b/tools/internal-rules/package.json
@@ -0,0 +1,8 @@
+{
+  "name": "eslint-plugin-internal-rules",
+  "version": "0.0.0",
+  "private": true,
+  "dependencies": {
+    "eslint-rule-composer": "^0.3.0"
+  }
+}
diff --git a/tools/rule-types.json b/tools/rule-types.json
index 44c1d48ab..1239e5f3f 100644
--- a/tools/rule-types.json
+++ b/tools/rule-types.json
@@ -222,6 +222,7 @@
     "prefer-arrow-callback": "suggestion",
     "prefer-const": "suggestion",
     "prefer-destructuring": "suggestion",
+    "prefer-named-capture-group": "suggestion",
     "prefer-numeric-literals": "suggestion",
     "prefer-object-spread": "suggestion",
     "prefer-promise-reject-errors": "suggestion",
@@ -264,4 +265,4 @@
     "wrap-regex": "layout",
     "yield-star-spacing": "layout",
     "yoda": "suggestion"
-}
\ No newline at end of file
+}
diff --git a/webpack.config.js b/webpack.config.js
index 134a657e7..1a6a2986a 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -2,22 +2,25 @@
 
 module.exports = {
     mode: "none",
-    entry: ["@babel/polyfill", "./lib/linter.js"],
+    entry: {
+        eslint: ["@babel/polyfill", "./lib/linter.js"],
+        espree: ["@babel/polyfill", "espree"]
+    },
     output: {
-        filename: "eslint.js",
-        library: "eslint",
+        filename: "[name].js",
+        library: "[name]",
         libraryTarget: "umd",
         globalObject: "this"
     },
     module: {
         rules: [
             {
-                test: /\.js$/u,
+                test: /\.m?js$/u,
                 loader: "babel-loader",
                 options: {
                     presets: ["@babel/preset-env"]
                 },
-                exclude: /node_modules/u
+                exclude: /node_modules\/lodash/u
             }
         ]
     },


Test patch:
diff --git a/lib/testers/rule-tester.js b/lib/testers/rule-tester.js
index 6d1bba989..f1d915531 100644
--- a/lib/testers/rule-tester.js
+++ b/lib/testers/rule-tester.js
@@ -379,7 +379,7 @@ class RuleTester {
                 }
             }
 
-            validator.validate(config, "rule-tester", ruleMap.get.bind(ruleMap), new Environments());
+            validator.validate(config, ruleMap.get.bind(ruleMap), new Environments(), "rule-tester");
 
             return {
                 messages: linter.verify(code, config, filename, true),
diff --git a/tests/lib/code-path-analysis/code-path.js b/tests/lib/code-path-analysis/code-path.js
index 6b90b57bf..be1039fb4 100644
--- a/tests/lib/code-path-analysis/code-path.js
+++ b/tests/lib/code-path-analysis/code-path.js
@@ -66,7 +66,7 @@ function getOrderOfTraversing(codePath, options, callback) {
 describe("CodePathAnalyzer", () => {
     describe(".traverseSegments()", () => {
         describe("should traverse segments from the first to the end:", () => {
-            /* eslint-disable rulesdir/multiline-comment-style */
+            /* eslint-disable internal-rules/multiline-comment-style */
             it("simple", () => {
                 const codePath = parseCodePaths("foo(); bar(); baz();")[0];
                 const order = getOrderOfTraversing(codePath);
diff --git a/tests/lib/config/config-validator.js b/tests/lib/config/config-validator.js
index 721533c10..9d4c39baf 100644
--- a/tests/lib/config/config-validator.js
+++ b/tests/lib/config/config-validator.js
@@ -108,7 +108,7 @@ describe("Validator", () => {
     describe("validate", () => {
 
         it("should do nothing with an empty config", () => {
-            validator.validate({}, "tests", ruleMapper, linter.environments);
+            validator.validate({}, ruleMapper, linter.environments, "tests");
         });
 
         it("should do nothing with a valid eslint config", () => {
@@ -124,9 +124,9 @@ describe("Validator", () => {
                     parserOptions: { foo: "bar" },
                     rules: {}
                 },
-                "tests",
                 ruleMapper,
-                linter.environments
+                linter.environments,
+                "tests"
             );
         });
 
@@ -136,9 +136,9 @@ describe("Validator", () => {
                 {
                     foo: true
                 },
-                "tests",
                 ruleMapper,
-                linter.environments
+                linter.environments,
+                "tests"
             );
 
             assert.throws(fn, "Unexpected top-level property \"foo\".");
@@ -146,13 +146,13 @@ describe("Validator", () => {
 
         describe("root", () => {
             it("should throw with a string value", () => {
-                const fn = validator.validate.bind(null, { root: "true" }, null, ruleMapper, linter.environments);
+                const fn = validator.validate.bind(null, { root: "true" }, ruleMapper, linter.environments, null);
 
                 assert.throws(fn, "Property \"root\" is the wrong type (expected boolean but got `\"true\"`).");
             });
 
             it("should throw with a numeric value", () => {
-                const fn = validator.validate.bind(null, { root: 0 }, null, ruleMapper, linter.environments);
+                const fn = validator.validate.bind(null, { root: 0 }, ruleMapper, linter.environments, null);
 
                 assert.throws(fn, "Property \"root\" is the wrong type (expected boolean but got `0`).");
             });
@@ -160,13 +160,13 @@ describe("Validator", () => {
 
         describe("globals", () => {
             it("should throw with a string value", () => {
-                const fn = validator.validate.bind(null, { globals: "jQuery" }, null, ruleMapper, linter.environments);
+                const fn = validator.validate.bind(null, { globals: "jQuery" }, ruleMapper, linter.environments, null);
 
                 assert.throws(fn, "Property \"globals\" is the wrong type (expected object but got `\"jQuery\"`).");
             });
 
             it("should throw with an array value", () => {
-                const fn = validator.validate.bind(null, { globals: ["jQuery"] }, null, ruleMapper, linter.environments);
+                const fn = validator.validate.bind(null, { globals: ["jQuery"] }, ruleMapper, linter.environments, null);
 
                 assert.throws(fn, "Property \"globals\" is the wrong type (expected object but got `[\"jQuery\"]`).");
             });
@@ -174,32 +174,32 @@ describe("Validator", () => {
 
         describe("parser", () => {
             it("should not throw with a null value", () => {
-                validator.validate({ parser: null }, null, ruleMapper, linter.environments);
+                validator.validate({ parser: null }, ruleMapper, linter.environments, null);
             });
         });
 
         describe("env", () => {
 
             it("should throw with an array environment", () => {
-                const fn = validator.validate.bind(null, { env: [] }, null, ruleMapper, linter.environments);
+                const fn = validator.validate.bind(null, { env: [] }, ruleMapper, linter.environments, null);
 
                 assert.throws(fn, "Property \"env\" is the wrong type (expected object but got `[]`).");
             });
 
             it("should throw with a primitive environment", () => {
-                const fn = validator.validate.bind(null, { env: 1 }, null, ruleMapper, linter.environments);
+                const fn = validator.validate.bind(null, { env: 1 }, ruleMapper, linter.environments, null);
 
                 assert.throws(fn, "Property \"env\" is the wrong type (expected object but got `1`).");
             });
 
             it("should catch invalid environments", () => {
-                const fn = validator.validate.bind(null, { env: { browser: true, invalid: true } }, null, ruleMapper, linter.environments);
+                const fn = validator.validate.bind(null, { env: { browser: true, invalid: true } }, ruleMapper, linter.environments, null);
 
                 assert.throws(fn, "Environment key \"invalid\" is unknown\n");
             });
 
             it("should catch disabled invalid environments", () => {
-                const fn = validator.validate.bind(null, { env: { browser: true, invalid: false } }, null, ruleMapper, linter.environments);
+                const fn = validator.validate.bind(null, { env: { browser: true, invalid: false } }, ruleMapper, linter.environments, null);
 
                 assert.throws(fn, "Environment key \"invalid\" is unknown\n");
             });
@@ -212,11 +212,11 @@ describe("Validator", () => {
 
         describe("plugins", () => {
             it("should not throw with an empty array", () => {
-                validator.validate({ plugins: [] }, null, ruleMapper, linter.environments);
+                validator.validate({ plugins: [] }, ruleMapper, linter.environments, null);
             });
 
             it("should throw with a string", () => {
-                const fn = validator.validate.bind(null, { plugins: "react" }, null, ruleMapper, linter.environments);
+                const fn = validator.validate.bind(null, { plugins: "react" }, ruleMapper, linter.environments, null);
 
                 assert.throws(fn, "Property \"plugins\" is the wrong type (expected array but got `\"react\"`).");
             });
@@ -224,11 +224,11 @@ describe("Validator", () => {
 
         describe("settings", () => {
             it("should not throw with an empty object", () => {
-                validator.validate({ settings: {} }, null, ruleMapper, linter.environments);
+                validator.validate({ settings: {} }, ruleMapper, linter.environments, null);
             });
 
             it("should throw with an array", () => {
-                const fn = validator.validate.bind(null, { settings: ["foo"] }, null, ruleMapper, linter.environments);
+                const fn = validator.validate.bind(null, { settings: ["foo"] }, ruleMapper, linter.environments, null);
 
                 assert.throws(fn, "Property \"settings\" is the wrong type (expected object but got `[\"foo\"]`).");
             });
@@ -236,15 +236,15 @@ describe("Validator", () => {
 
         describe("extends", () => {
             it("should not throw with an empty array", () => {
-                validator.validate({ extends: [] }, null, ruleMapper, linter.environments);
+                validator.validate({ extends: [] }, ruleMapper, linter.environments, null);
             });
 
             it("should not throw with a string", () => {
-                validator.validate({ extends: "react" }, null, ruleMapper, linter.environments);
+                validator.validate({ extends: "react" }, ruleMapper, linter.environments, null);
             });
 
             it("should throw with an object", () => {
-                const fn = validator.validate.bind(null, { extends: {} }, null, ruleMapper, linter.environments);
+                const fn = validator.validate.bind(null, { extends: {} }, ruleMapper, linter.environments, null);
 
                 assert.throws(fn, "Property \"extends\" is the wrong type (expected string/array but got `{}`).");
             });
@@ -252,11 +252,11 @@ describe("Validator", () => {
 
         describe("parserOptions", () => {
             it("should not throw with an empty object", () => {
-                validator.validate({ parserOptions: {} }, null, ruleMapper, linter.environments);
+                validator.validate({ parserOptions: {} }, ruleMapper, linter.environments, null);
             });
 
             it("should throw with an array", () => {
-                const fn = validator.validate.bind(null, { parserOptions: ["foo"] }, null, ruleMapper, linter.environments);
+                const fn = validator.validate.bind(null, { parserOptions: ["foo"] }, ruleMapper, linter.environments, null);
 
                 assert.throws(fn, "Property \"parserOptions\" is the wrong type (expected object but got `[\"foo\"]`).");
             });
@@ -265,47 +265,47 @@ describe("Validator", () => {
         describe("rules", () => {
 
             it("should do nothing with an empty rules object", () => {
-                validator.validate({ rules: {} }, "tests", ruleMapper, linter.environments);
+                validator.validate({ rules: {} }, ruleMapper, linter.environments, "tests");
             });
 
             it("should do nothing with a valid config with rules", () => {
-                validator.validate({ rules: { "mock-rule": [2, "second"] } }, "tests", ruleMapper, linter.environments);
+                validator.validate({ rules: { "mock-rule": [2, "second"] } }, ruleMapper, linter.environments, "tests");
             });
 
             it("should do nothing with a valid config when severity is off", () => {
-                validator.validate({ rules: { "mock-rule": ["off", "second"] } }, "tests", ruleMapper, linter.environments);
+                validator.validate({ rules: { "mock-rule": ["off", "second"] } }, ruleMapper, linter.environments, "tests");
             });
 
             it("should do nothing with an invalid config when severity is off", () => {
-                validator.validate({ rules: { "mock-required-options-rule": "off" } }, "tests", ruleMapper, linter.environments);
+                validator.validate({ rules: { "mock-required-options-rule": "off" } }, ruleMapper, linter.environments, "tests");
             });
 
             it("should do nothing with an invalid config when severity is an array with 'off'", () => {
-                validator.validate({ rules: { "mock-required-options-rule": ["off"] } }, "tests", ruleMapper, linter.environments);
+                validator.validate({ rules: { "mock-required-options-rule": ["off"] } }, ruleMapper, linter.environments, "tests");
             });
 
             it("should do nothing with a valid config when severity is warn", () => {
-                validator.validate({ rules: { "mock-rule": ["warn", "second"] } }, "tests", ruleMapper, linter.environments);
+                validator.validate({ rules: { "mock-rule": ["warn", "second"] } }, ruleMapper, linter.environments, "tests");
             });
 
             it("should do nothing with a valid config when severity is error", () => {
-                validator.validate({ rules: { "mock-rule": ["error", "second"] } }, "tests", ruleMapper, linter.environments);
+                validator.validate({ rules: { "mock-rule": ["error", "second"] } }, ruleMapper, linter.environments, "tests");
             });
 
             it("should do nothing with a valid config when severity is Off", () => {
-                validator.validate({ rules: { "mock-rule": ["Off", "second"] } }, "tests", ruleMapper, linter.environments);
+                validator.validate({ rules: { "mock-rule": ["Off", "second"] } }, ruleMapper, linter.environments, "tests");
             });
 
             it("should do nothing with a valid config when severity is Warn", () => {
-                validator.validate({ rules: { "mock-rule": ["Warn", "second"] } }, "tests", ruleMapper, linter.environments);
+                validator.validate({ rules: { "mock-rule": ["Warn", "second"] } }, ruleMapper, linter.environments, "tests");
             });
 
             it("should do nothing with a valid config when severity is Error", () => {
-                validator.validate({ rules: { "mock-rule": ["Error", "second"] } }, "tests", ruleMapper, linter.environments);
+                validator.validate({ rules: { "mock-rule": ["Error", "second"] } }, ruleMapper, linter.environments, "tests");
             });
 
             it("should catch invalid rule options", () => {
-                const fn = validator.validate.bind(null, { rules: { "mock-rule": [3, "third"] } }, "tests", ruleMapper, linter.environments);
+                const fn = validator.validate.bind(null, { rules: { "mock-rule": [3, "third"] } }, ruleMapper, linter.environments, "tests");
 
                 assert.throws(fn, "tests:\n\tConfiguration for rule \"mock-rule\" is invalid:\n\tSeverity should be one of the following: 0 = off, 1 = warn, 2 = error (you passed '3').\n");
             });
@@ -313,13 +313,13 @@ describe("Validator", () => {
             it("should allow for rules with no options", () => {
                 linter.defineRule("mock-no-options-rule", mockNoOptionsRule);
 
-                validator.validate({ rules: { "mock-no-options-rule": 2 } }, "tests", ruleMapper, linter.environments);
+                validator.validate({ rules: { "mock-no-options-rule": 2 } }, ruleMapper, linter.environments, "tests");
             });
 
             it("should not allow options for rules with no options", () => {
                 linter.defineRule("mock-no-options-rule", mockNoOptionsRule);
 
-                const fn = validator.validate.bind(null, { rules: { "mock-no-options-rule": [2, "extra"] } }, "tests", ruleMapper, linter.environments);
+                const fn = validator.validate.bind(null, { rules: { "mock-no-options-rule": [2, "extra"] } }, ruleMapper, linter.environments, "tests");
 
                 assert.throws(fn, "tests:\n\tConfiguration for rule \"mock-no-options-rule\" is invalid:\n\tValue [\"extra\"] should NOT have more than 0 items.\n");
             });
@@ -327,39 +327,39 @@ describe("Validator", () => {
 
         describe("overrides", () => {
             it("should not throw with an empty overrides array", () => {
-                validator.validate({ overrides: [] }, "tests", ruleMapper, linter.environments);
+                validator.validate({ overrides: [] }, ruleMapper, linter.environments, "tests");
             });
 
             it("should not throw with a valid overrides array", () => {
-                validator.validate({ overrides: [{ files: "*", rules: {} }] }, "tests", ruleMapper, linter.environments);
+                validator.validate({ overrides: [{ files: "*", rules: {} }] }, ruleMapper, linter.environments, "tests");
             });
 
             it("should throw if override does not specify files", () => {
-                const fn = validator.validate.bind(null, { overrides: [{ rules: {} }] }, "tests", ruleMapper, linter.environments);
+                const fn = validator.validate.bind(null, { overrides: [{ rules: {} }] }, ruleMapper, linter.environments, "tests");
 
                 assert.throws(fn, "ESLint configuration in tests is invalid:\n\t- \"overrides[0]\" should have required property 'files'. Value: {\"rules\":{}}.\n");
             });
 
             it("should throw if override has an empty files array", () => {
-                const fn = validator.validate.bind(null, { overrides: [{ files: [] }] }, "tests", ruleMapper, linter.environments);
+                const fn = validator.validate.bind(null, { overrides: [{ files: [] }] }, ruleMapper, linter.environments, "tests");
 
                 assert.throws(fn, "ESLint configuration in tests is invalid:\n\t- Property \"overrides[0].files\" is the wrong type (expected string but got `[]`).\n\t- \"overrides[0].files\" should NOT have fewer than 1 items. Value: [].\n\t- \"overrides[0].files\" should match exactly one schema in oneOf. Value: [].\n");
             });
 
             it("should throw if override has nested overrides", () => {
-                const fn = validator.validate.bind(null, { overrides: [{ files: "*", overrides: [{ files: "*", rules: {} }] }] }, "tests", ruleMapper, linter.environments);
+                const fn = validator.validate.bind(null, { overrides: [{ files: "*", overrides: [{ files: "*", rules: {} }] }] }, ruleMapper, linter.environments, "tests");
 
                 assert.throws(fn, "ESLint configuration in tests is invalid:\n\t- Unexpected top-level property \"overrides[0].overrides\".\n");
             });
 
             it("should throw if override extends", () => {
-                const fn = validator.validate.bind(null, { overrides: [{ files: "*", extends: "eslint-recommended" }] }, "tests", ruleMapper, linter.environments);
+                const fn = validator.validate.bind(null, { overrides: [{ files: "*", extends: "eslint-recommended" }] }, ruleMapper, linter.environments, "tests");
 
                 assert.throws(fn, "ESLint configuration in tests is invalid:\n\t- Unexpected top-level property \"overrides[0].extends\".\n");
             });
 
             it("should throw if override tries to set root", () => {
-                const fn = validator.validate.bind(null, { overrides: [{ files: "*", root: "true" }] }, "tests", ruleMapper, linter.environments);
+                const fn = validator.validate.bind(null, { overrides: [{ files: "*", root: "true" }] }, ruleMapper, linter.environments, "tests");
 
                 assert.throws(fn, "ESLint configuration in tests is invalid:\n\t- Unexpected top-level property \"overrides[0].root\".\n");
             });
@@ -367,13 +367,13 @@ describe("Validator", () => {
             describe("env", () => {
 
                 it("should catch invalid environments", () => {
-                    const fn = validator.validate.bind(null, { overrides: [{ files: "*", env: { browser: true, invalid: true } }] }, null, ruleMapper, linter.environments);
+                    const fn = validator.validate.bind(null, { overrides: [{ files: "*", env: { browser: true, invalid: true } }] }, ruleMapper, linter.environments, null);
 
                     assert.throws(fn, "Environment key \"invalid\" is unknown\n");
                 });
 
                 it("should catch disabled invalid environments", () => {
-                    const fn = validator.validate.bind(null, { overrides: [{ files: "*", env: { browser: true, invalid: false } }] }, null, ruleMapper, linter.environments);
+                    const fn = validator.validate.bind(null, { overrides: [{ files: "*", env: { browser: true, invalid: false } }] }, ruleMapper, linter.environments, null);
 
                     assert.throws(fn, "Environment key \"invalid\" is unknown\n");
                 });
@@ -383,7 +383,7 @@ describe("Validator", () => {
             describe("rules", () => {
 
                 it("should catch invalid rule options", () => {
-                    const fn = validator.validate.bind(null, { overrides: [{ files: "*", rules: { "mock-rule": [3, "third"] } }] }, "tests", ruleMapper, linter.environments);
+                    const fn = validator.validate.bind(null, { overrides: [{ files: "*", rules: { "mock-rule": [3, "third"] } }] }, ruleMapper, linter.environments, "tests");
 
                     assert.throws(fn, "tests:\n\tConfiguration for rule \"mock-rule\" is invalid:\n\tSeverity should be one of the following: 0 = off, 1 = warn, 2 = error (you passed '3').\n");
                 });
@@ -391,7 +391,7 @@ describe("Validator", () => {
                 it("should not allow options for rules with no options", () => {
                     linter.defineRule("mock-no-options-rule", mockNoOptionsRule);
 
-                    const fn = validator.validate.bind(null, { overrides: [{ files: "*", rules: { "mock-no-options-rule": [2, "extra"] } }] }, "tests", ruleMapper, linter.environments);
+                    const fn = validator.validate.bind(null, { overrides: [{ files: "*", rules: { "mock-no-options-rule": [2, "extra"] } }] }, ruleMapper, linter.environments, "tests");
 
                     assert.throws(fn, "tests:\n\tConfiguration for rule \"mock-no-options-rule\" is invalid:\n\tValue [\"extra\"] should NOT have more than 0 items.\n");
                 });
diff --git a/tests/lib/rules/_utils.js b/tests/lib/rules/_utils.js
new file mode 100644
index 000000000..a1b642727
--- /dev/null
+++ b/tests/lib/rules/_utils.js
@@ -0,0 +1,25 @@
+/**
+ * @fileoverview uitls for rule tests.
+ * @author 唯然<weiran.zsd@outlook.com>
+ */
+
+"use strict";
+
+/**
+ * Prevents leading spaces in a multiline template literal from appearing in the resulting string
+ * @param {string[]} strings The strings in the template literal
+ * @returns {string} The template literal, with spaces removed from all lines
+ */
+function unIndent(strings) {
+    const templateValue = strings[0];
+    const lines = templateValue.replace(/^\n/u, "").replace(/\n\s*$/u, "").split("\n");
+    const lineIndents = lines.filter(line => line.trim()).map(line => line.match(/ */u)[0].length);
+    const minLineIndent = Math.min(...lineIndents);
+
+    return lines.map(line => line.slice(minLineIndent)).join("\n");
+}
+
+
+module.exports = {
+    unIndent
+};
diff --git a/tests/lib/rules/complexity.js b/tests/lib/rules/complexity.js
index 159d27c8c..93e404468 100644
--- a/tests/lib/rules/complexity.js
+++ b/tests/lib/rules/complexity.js
@@ -106,6 +106,11 @@ ruleTester.run("complexity", rule, {
             code: createComplexity(21),
             errors: [makeError("Function 'test'", 21)]
         },
+        {
+            code: createComplexity(21),
+            options: [{}],
+            errors: [makeError("Function 'test'", 21)]
+        },
 
         // object property options
         { code: "function a(x) {}", options: [{ max: 0 }], errors: [makeError("Function 'a'", 1)] }
diff --git a/tests/lib/rules/indent.js b/tests/lib/rules/indent.js
index 9ce941fb2..45abc654d 100644
--- a/tests/lib/rules/indent.js
+++ b/tests/lib/rules/indent.js
@@ -21,6 +21,8 @@ const path = require("path");
 const fixture = fs.readFileSync(path.join(__dirname, "../../fixtures/rules/indent/indent-invalid-fixture-1.js"), "utf8");
 const fixedFixture = fs.readFileSync(path.join(__dirname, "../../fixtures/rules/indent/indent-valid-fixture-1.js"), "utf8");
 const parser = require("../../fixtures/fixture-parser");
+const { unIndent } = require("./_utils");
+
 
 /**
  * Create error message object for failure cases with a single 'found' indentation type
@@ -54,20 +56,6 @@ function expectedErrors(providedIndentType, providedErrors) {
     }));
 }
 
-/**
- * Prevents leading spaces in a multiline template literal from appearing in the resulting string
- * @param {string[]} strings The strings in the template literal
- * @returns {string} The template literal, with spaces removed from all lines
- */
-function unIndent(strings) {
-    const templateValue = strings[0];
-    const lines = templateValue.replace(/^\n/u, "").replace(/\n\s*$/u, "").split("\n");
-    const lineIndents = lines.filter(line => line.trim()).map(line => line.match(/ */u)[0].length);
-    const minLineIndent = Math.min(...lineIndents);
-
-    return lines.map(line => line.slice(minLineIndent)).join("\n");
-}
-
 const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 8, ecmaFeatures: { jsx: true } } });
 
 ruleTester.run("indent", rule, {
diff --git a/tests/lib/rules/line-comment-position.js b/tests/lib/rules/line-comment-position.js
index 6dfe48561..8a4d07af1 100644
--- a/tests/lib/rules/line-comment-position.js
+++ b/tests/lib/rules/line-comment-position.js
@@ -80,6 +80,10 @@ ruleTester.run("line-comment-position", rule, {
         {
             code: "// above\n1 + 1; // ignored",
             options: [{ ignorePattern: "ignored" }]
+        },
+        {
+            code: "foo; // eslint-disable-line no-alert",
+            options: [{ position: "above" }]
         }
     ],
 
diff --git a/tests/lib/rules/max-depth.js b/tests/lib/rules/max-depth.js
index 086abec58..06029021b 100644
--- a/tests/lib/rules/max-depth.js
+++ b/tests/lib/rules/max-depth.js
@@ -38,6 +38,9 @@ ruleTester.run("max-depth", rule, {
         { code: "function foo() { if (true) { if (false) { if (true) { if (false) { if (true) { } } } } } }", errors: [{ messageId: "tooDeeply", data: { depth: 5 }, type: "IfStatement" }] },
 
         // object property options
-        { code: "function foo() { if (true) { if (false) { if (true) { } } } }", options: [{ max: 2 }], errors: [{ messageId: "tooDeeply", data: { depth: 3 }, type: "IfStatement" }] }
+        { code: "function foo() { if (true) { if (false) { if (true) { } } } }", options: [{ max: 2 }], errors: [{ messageId: "tooDeeply", data: { depth: 3 }, type: "IfStatement" }] },
+
+        { code: "function foo() { if (a) { if (b) { if (c) { if (d) { if (e) {} } } } } }", options: [{}], errors: [{ messageId: "tooDeeply", data: { depth: 5 } }] },
+        { code: "function foo() { if (true) {} }", options: [{ max: 0 }], errors: [{ messageId: "tooDeeply", data: { depth: 1 } }] }
     ]
 });
diff --git a/tests/lib/rules/max-lines.js b/tests/lib/rules/max-lines.js
index 8324b51e1..33f837daa 100644
--- a/tests/lib/rules/max-lines.js
+++ b/tests/lib/rules/max-lines.js
@@ -148,6 +148,16 @@ ruleTester.run("max-lines", rule, {
             ].join("\n"),
             options: [{ max: 2, skipBlankLines: true }],
             errors: [{ messageId: "exceed", data: { max: 2, actual: 6 } }]
+        },
+        {
+            code: "AAAAAAAA\n".repeat(301).trim(),
+            options: [{}],
+            errors: [{ messageId: "exceed", data: { max: 300, actual: 301 } }]
+        },
+        {
+            code: "A",
+            options: [{ max: 0 }],
+            errors: [{ messageId: "exceed", data: { max: 0, actual: 1 } }]
         }
     ]
 });
diff --git a/tests/lib/rules/max-nested-callbacks.js b/tests/lib/rules/max-nested-callbacks.js
index af17ab3b6..91ff8f99a 100644
--- a/tests/lib/rules/max-nested-callbacks.js
+++ b/tests/lib/rules/max-nested-callbacks.js
@@ -75,6 +75,16 @@ ruleTester.run("max-nested-callbacks", rule, {
             code: nestFunctions(11),
             errors: [{ messageId: "exceed", data: { num: 11, max: 10 }, type: "FunctionExpression" }]
         },
+        {
+            code: nestFunctions(11),
+            options: [{}],
+            errors: [{ messageId: "exceed", data: { num: 11, max: 10 }, type: "FunctionExpression" }]
+        },
+        {
+            code: "foo(function() {})",
+            options: [{ max: 0 }],
+            errors: [{ messageId: "exceed", data: { num: 1, max: 0 } }]
+        },
 
         // object property options
         {
diff --git a/tests/lib/rules/max-params.js b/tests/lib/rules/max-params.js
index bdbc8efa0..206ed714f 100644
--- a/tests/lib/rules/max-params.js
+++ b/tests/lib/rules/max-params.js
@@ -94,6 +94,22 @@ ruleTester.run("max-params", rule, {
                 type: "FunctionDeclaration"
             }]
         },
+        {
+            code: "function test(a, b, c, d) {}",
+            options: [{}],
+            errors: [{
+                messageId: "exceed",
+                data: { name: "Function 'test'", count: 4, max: 3 }
+            }]
+        },
+        {
+            code: "function test(a) {}",
+            options: [{ max: 0 }],
+            errors: [{
+                messageId: "exceed",
+                data: { name: "Function 'test'", count: 1, max: 0 }
+            }]
+        },
 
         // Error location should not cover the entire function; just the name.
         {
diff --git a/tests/lib/rules/max-statements.js b/tests/lib/rules/max-statements.js
index 53567448f..2c66ee04c 100644
--- a/tests/lib/rules/max-statements.js
+++ b/tests/lib/rules/max-statements.js
@@ -133,6 +133,16 @@ ruleTester.run("max-statements", rule, {
             code: "var foo = { thing: function() { var bar = 1; var baz = 2; var baz2; } }",
             options: [{ max: 2 }],
             errors: [{ messageId: "exceed", data: { name: "Method 'thing'", count: "3", max: 2 } }]
+        },
+        {
+            code: "function foo() { 1; 2; 3; 4; 5; 6; 7; 8; 9; 10; 11; }",
+            options: [{}],
+            errors: [{ messageId: "exceed", data: { name: "Function 'foo'", count: 11, max: 10 } }]
+        },
+        {
+            code: "function foo() { 1; }",
+            options: [{ max: 0 }],
+            errors: [{ messageId: "exceed", data: { name: "Function 'foo'", count: 1, max: 0 } }]
         }
     ]
 });
diff --git a/tests/lib/rules/no-extra-parens.js b/tests/lib/rules/no-extra-parens.js
index b3481d06a..366a6c39b 100644
--- a/tests/lib/rules/no-extra-parens.js
+++ b/tests/lib/rules/no-extra-parens.js
@@ -452,6 +452,7 @@ ruleTester.run("no-extra-parens", rule, {
         "({}) ? foo() : bar()",
         "({}) + foo",
         "(function(){}) + foo",
+        "(let)\nfoo",
         "(let[foo]) = 1", // setting the 'foo' property of the 'let' variable to 1
         {
             code: "((function(){}).foo.bar)();",
@@ -1092,6 +1093,18 @@ ruleTester.run("no-extra-parens", rule, {
             "Identifier",
             1
         ),
-        invalid("for (a in (b, c));", "for (a in b, c);", "SequenceExpression", null)
+        invalid("for (a in (b, c));", "for (a in b, c);", "SequenceExpression", null),
+        invalid(
+            "(let)",
+            "let",
+            "Identifier",
+            1
+        ),
+        invalid(
+            "((let))",
+            "(let)",
+            "Identifier",
+            1
+        )
     ]
 });
diff --git a/tests/lib/rules/no-warning-comments.js b/tests/lib/rules/no-warning-comments.js
index 3484d0a45..8a9b2c5e2 100644
--- a/tests/lib/rules/no-warning-comments.js
+++ b/tests/lib/rules/no-warning-comments.js
@@ -36,7 +36,8 @@ ruleTester.run("no-warning-comments", rule, {
         { code: "// comments containing terms as substrings like TodoMVC", options: [{ terms: ["todo"], location: "anywhere" }] },
         { code: "// special regex characters don't cause problems", options: [{ terms: ["[aeiou]"], location: "anywhere" }] },
         "/*eslint no-warning-comments: [2, { \"terms\": [\"todo\", \"fixme\", \"any other term\"], \"location\": \"anywhere\" }]*/\n\nvar x = 10;\n",
-        { code: "/*eslint no-warning-comments: [2, { \"terms\": [\"todo\", \"fixme\", \"any other term\"], \"location\": \"anywhere\" }]*/\n\nvar x = 10;\n", options: [{ location: "anywhere" }] }
+        { code: "/*eslint no-warning-comments: [2, { \"terms\": [\"todo\", \"fixme\", \"any other term\"], \"location\": \"anywhere\" }]*/\n\nvar x = 10;\n", options: [{ location: "anywhere" }] },
+        { code: "foo", options: [{ terms: ["foo-bar"] }] }
     ],
     invalid: [
         { code: "// fixme", errors: [{ message: "Unexpected 'fixme' comment." }] },
diff --git a/tests/lib/rules/one-var.js b/tests/lib/rules/one-var.js
index ec7aa9338..bec330c3c 100644
--- a/tests/lib/rules/one-var.js
+++ b/tests/lib/rules/one-var.js
@@ -491,15 +491,11 @@ ruleTester.run("one-var", rule, {
         },
         {
             code: "var a; somethingElse(); var b;",
-            output: null,
-            options: [{ var: "never" }],
-            errors: null
+            options: [{ var: "never" }]
         },
         {
             code: "var foo = 1;\nlet bar = function() { var x; };\nvar baz = 2;",
-            output: null,
-            options: [{ var: "never" }],
-            errors: null
+            options: [{ var: "never" }]
         }
     ],
     invalid: [
diff --git a/tests/lib/rules/prefer-named-capture-group.js b/tests/lib/rules/prefer-named-capture-group.js
new file mode 100644
index 000000000..88047d7c9
--- /dev/null
+++ b/tests/lib/rules/prefer-named-capture-group.js
@@ -0,0 +1,95 @@
+/**
+ * @fileoverview Tests for prefer-named-capture-group rule.
+ * @author Pig Fang <https://github.com/g-plane>
+ */
+
+"use strict";
+
+//------------------------------------------------------------------------------
+// Requirements
+//------------------------------------------------------------------------------
+
+const rule = require("../../../lib/rules/prefer-named-capture-group"),
+    RuleTester = require("../../../lib/testers/rule-tester");
+
+//------------------------------------------------------------------------------
+// Tests
+//------------------------------------------------------------------------------
+
+const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 2018 } });
+
+ruleTester.run("prefer-named-capture-group", rule, {
+    valid: [
+        "/normal_regex/",
+        "/(?:[0-9]{4})/",
+        "/(?<year>[0-9]{4})/",
+        "/\\u{1F680}/u",
+        "new RegExp()",
+        "new RegExp(foo)",
+        "new RegExp('')",
+        "new RegExp('(?<year>[0-9]{4})')",
+        "RegExp()",
+        "RegExp(foo)",
+        "RegExp('')",
+        "RegExp('(?<year>[0-9]{4})')",
+        "RegExp('(')", // invalid regexp should be ignored
+        "RegExp('\\\\u{1F680}', 'u')"
+    ],
+
+    invalid: [
+        {
+            code: "/([0-9]{4})/",
+            errors: [{
+                messageId: "required",
+                type: "Literal",
+                data: { group: "([0-9]{4})" },
+                line: 1,
+                column: 2,
+                endColumn: 12
+            }]
+        },
+        {
+            code: "new RegExp('([0-9]{4})')",
+            errors: [{
+                messageId: "required",
+                type: "NewExpression",
+                data: { group: "([0-9]{4})" },
+                line: 1,
+                column: 13,
+                endColumn: 23
+            }]
+        },
+        {
+            code: "RegExp('([0-9]{4})')",
+            errors: [{
+                messageId: "required",
+                type: "CallExpression",
+                data: { group: "([0-9]{4})" },
+                line: 1,
+                column: 9,
+                endColumn: 19
+            }]
+        },
+        {
+            code: "/([0-9]{4})-(\\w{5})/",
+            errors: [
+                {
+                    messageId: "required",
+                    type: "Literal",
+                    data: { group: "([0-9]{4})" },
+                    line: 1,
+                    column: 2,
+                    endColumn: 12
+                },
+                {
+                    messageId: "required",
+                    type: "Literal",
+                    data: { group: "(\\w{5})" },
+                    line: 1,
+                    column: 13,
+                    endColumn: 20
+                }
+            ]
+        }
+    ]
+});