Repository: eslint/eslint
Pull request #9309 (2017-09-15 13:17:43)

Docs: fix wrong config in max-len example.
<!--
    ESLint adheres to the [JS Foundation Code of Conduct](https://js.foundation/community/code-of-conduct).
-->

**What is the purpose of this pull request? (put an "X" next to item)**

[x] Documentation update

<!--
    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 (http://eslint.org/docs/developer-guide/contributing/pull-requests)
    - Include tests for this change
    - Update documentation for this change (if appropriate)
-->

<!--
    The following is required for all pull requests:
-->

**What changes did you make? (Give an overview)**
this regex will cause an error:
![image](https://user-images.githubusercontent.com/13050025/30484160-1e0989ce-9a5c-11e7-8476-89b532ba6604.png)


**Is there anything you'd like reviewers to focus on?**

```js
new RegExp("^\\s*var\\s.+=\\s*require\\s*\\(/");
```

it didn't cause an error, but when apply the config, it didn't work. is this expected?



eslintbot: LGTM
eslintbot: LGTM

Patch:
diff --git a/docs/rules/max-len.md b/docs/rules/max-len.md
index ef463b2ea..55a41fcfa 100644
--- a/docs/rules/max-len.md
+++ b/docs/rules/max-len.md
@@ -144,10 +144,10 @@ var longRegExpLiteral = /this is a really really really really really long regul
 
 ### ignorePattern
 
-Examples of **correct** code for this rule with the `{ "ignorePattern": true }` option:
+Examples of **correct** code for this rule with the `ignorePattern` option:
 
 ```js
-/*eslint max-len: ["error", { "ignorePattern": "^\\s*var\\s.+=\\s*require\\s*\\(/" }]*/
+/*eslint max-len: ["error", { "ignorePattern": "^\\s*var\\s.+=\\s*require\\s*\(" }]*/
 
 var dep = require('really/really/really/really/really/really/really/really/long/module');
 ```
diff --git a/docs/rules/prefer-arrow-callback.md b/docs/rules/prefer-arrow-callback.md
index 95ef16b3a..c9132122e 100644
--- a/docs/rules/prefer-arrow-callback.md
+++ b/docs/rules/prefer-arrow-callback.md
@@ -76,7 +76,7 @@ By default `{ "allowUnboundThis": true }`, this `boolean` option allows function
 
 When set to `false` this option prohibits the use of function expressions as callbacks or function arguments entirely, without exception.
 
-`{ "allowNamedFunctions": false }` **will** flag the following examples:
+`{ "allowUnboundThis": false }` **will** flag the following examples:
 
 ```js
 /* eslint prefer-arrow-callback: [ "error", { "allowUnboundThis": false } ] */
diff --git a/lib/cli-engine.js b/lib/cli-engine.js
index 054048038..2814d38b7 100644
--- a/lib/cli-engine.js
+++ b/lib/cli-engine.js
@@ -394,13 +394,9 @@ class CLIEngine {
             });
         }
 
-        if (this.options.rules && Object.keys(this.options.rules).length) {
-            const loadedRules = this.linter.getRules();
-
-            Object.keys(this.options.rules).filter(ruleId => loadedRules.has(ruleId)).forEach(name => {
-                validator.validateRuleOptions(loadedRules.get(name), name, this.options.rules[name], "CLI");
-            });
-        }
+        Object.keys(this.options.rules || {}).forEach(name => {
+            validator.validateRuleOptions(name, this.options.rules[name], "CLI", this.linter.rules);
+        });
 
         this.config = new Config(this.options, this.linter);
     }
diff --git a/lib/config/config-file.js b/lib/config/config-file.js
index e74fd4640..87412dd2a 100644
--- a/lib/config/config-file.js
+++ b/lib/config/config-file.js
@@ -546,7 +546,7 @@ function loadFromDisk(resolvedPath, configContext) {
         }
 
         // validate the configuration before continuing
-        validator.validate(config, resolvedPath.configFullName, configContext.linterContext.getRules(), configContext.linterContext.environments);
+        validator.validate(config, resolvedPath.configFullName, configContext.linterContext.rules, configContext.linterContext.environments);
 
         /*
          * 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 c06354e77..22bc1efbd 100644
--- a/lib/config/config-validator.js
+++ b/lib/config/config-validator.js
@@ -14,7 +14,9 @@ const ajv = require("../util/ajv"),
     configSchema = require("../../conf/config-schema.js"),
     util = require("util");
 
-const ruleValidators = new WeakMap();
+const validators = {
+    rules: Object.create(null)
+};
 
 //------------------------------------------------------------------------------
 // Private
@@ -23,11 +25,13 @@ let validateSchema;
 
 /**
  * Gets a complete options schema for a rule.
- * @param {{create: Function, schema: (Array|null)}} rule A new-style rule object
+ * @param {string} id The rule's unique name.
+ * @param {Rules} rulesContext Rule context
  * @returns {Object} JSON Schema for the rule's options.
  */
-function getRuleOptionsSchema(rule) {
-    const schema = rule.schema || rule.meta && rule.meta.schema;
+function getRuleOptionsSchema(id, rulesContext) {
+    const rule = rulesContext.get(id),
+        schema = rule && rule.schema || rule && rule.meta && rule.meta.schema;
 
     // Given a tuple of schemas, insert warning level at the beginning
     if (Array.isArray(schema)) {
@@ -68,20 +72,19 @@ function validateRuleSeverity(options) {
 
 /**
 * Validates the non-severity options passed to a rule, based on its schema.
-* @param {{create: Function}} rule The rule to validate
+* @param {string} id The rule's unique name
 * @param {array} localOptions The options for the rule, excluding severity
+* @param {Rules} rulesContext Rule context
 * @returns {void}
 */
-function validateRuleSchema(rule, localOptions) {
-    if (!ruleValidators.has(rule)) {
-        const schema = getRuleOptionsSchema(rule);
+function validateRuleSchema(id, localOptions, rulesContext) {
+    const schema = getRuleOptionsSchema(id, rulesContext);
 
-        if (schema) {
-            ruleValidators.set(rule, ajv.compile(schema));
-        }
+    if (!validators.rules[id] && schema) {
+        validators.rules[id] = ajv.compile(schema);
     }
 
-    const validateRule = ruleValidators.get(rule);
+    const validateRule = validators.rules[id];
 
     if (validateRule) {
         validateRule(localOptions);
@@ -93,21 +96,21 @@ function validateRuleSchema(rule, localOptions) {
 
 /**
  * Validates a rule's options against its schema.
- * @param {{create: Function}} rule The rule that the config is being validated for
- * @param {string} ruleId The rule's unique name.
+ * @param {string} id The rule's unique name.
  * @param {array|number} options The given options for the rule.
  * @param {string} source The name of the configuration source to report in any errors.
+ * @param {Rules} rulesContext Rule context
  * @returns {void}
  */
-function validateRuleOptions(rule, ruleId, options, source) {
+function validateRuleOptions(id, options, source, rulesContext) {
     try {
         const severity = validateRuleSeverity(options);
 
         if (severity !== 0 && !(typeof severity === "string" && severity.toLowerCase() === "off")) {
-            validateRuleSchema(rule, Array.isArray(options) ? options.slice(1) : []);
+            validateRuleSchema(id, Array.isArray(options) ? options.slice(1) : [], rulesContext);
         }
     } catch (err) {
-        throw new Error(`${source}:\n\tConfiguration for rule "${ruleId}" is invalid:\n${err.message}`);
+        throw new Error(`${source}:\n\tConfiguration for rule "${id}" is invalid:\n${err.message}`);
     }
 }
 
@@ -138,16 +141,16 @@ 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 {Map<string, {create: Function}>} rulesMap A map from strings to loaded rules
+ * @param {Rules} rulesContext Rule context
  * @returns {void}
  */
-function validateRules(rulesConfig, source, rulesMap) {
+function validateRules(rulesConfig, source, rulesContext) {
     if (!rulesConfig) {
         return;
     }
 
-    Object.keys(rulesConfig).filter(id => rulesMap.has(id)).forEach(id => {
-        validateRuleOptions(rulesMap.get(id), id, rulesConfig[id], source);
+    Object.keys(rulesConfig).forEach(id => {
+        validateRuleOptions(id, rulesConfig[id], source, rulesContext);
     });
 }
 
@@ -218,13 +221,13 @@ 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 {Map<string, {create: Function}>} ruleMap A map from rule IDs to defined rules
+ * @param {Rules} rulesContext The rules context
  * @param {Environments} envContext The env context
  * @returns {void}
  */
-function validate(config, source, ruleMap, envContext) {
+function validate(config, source, rulesContext, envContext) {
     validateConfigSchema(config, source);
-    validateRules(config.rules, source, ruleMap);
+    validateRules(config.rules, source, rulesContext);
     validateEnvironment(config.env, source, envContext);
 }
 
diff --git a/lib/linter.js b/lib/linter.js
index afbf83abf..b362a59ab 100755
--- a/lib/linter.js
+++ b/lib/linter.js
@@ -275,7 +275,7 @@ function createDisableDirectives(type, loc, value) {
  * @param {string} filename The file being checked.
  * @param {ASTNode} ast The top node of the AST.
  * @param {Object} config The existing configuration data.
- * @param {Map<string, {create: Function}>} ruleMap A map from rule IDs to defined rules
+ * @param {Linter} linterContext Linter context object
  * @returns {{
  *      config: Object,
  *      problems: Problem[],
@@ -288,9 +288,9 @@ function createDisableDirectives(type, loc, value) {
  * }} Modified config object, along with any problems encountered
  * while parsing config comments
  */
-function modifyConfigsFromComments(filename, ast, config, ruleMap) {
+function modifyConfigsFromComments(filename, ast, config, linterContext) {
 
-    const commentConfig = {
+    let commentConfig = {
         exported: {},
         astGlobals: {},
         rules: {},
@@ -338,9 +338,7 @@ function modifyConfigsFromComments(filename, ast, config, ruleMap) {
                             Object.keys(parseResult.config).forEach(name => {
                                 const ruleValue = parseResult.config[name];
 
-                                if (ruleMap.has(name)) {
-                                    validator.validateRuleOptions(ruleMap.get(name), name, ruleValue, `${filename} line ${comment.loc.start.line}`);
-                                }
+                                validator.validateRuleOptions(name, ruleValue, `${filename} line ${comment.loc.start.line}`, linterContext.rules);
                                 commentRules[name] = ruleValue;
                             });
                         } else {
@@ -362,6 +360,14 @@ function modifyConfigsFromComments(filename, ast, config, ruleMap) {
         }
     });
 
+    // apply environment configs
+    Object.keys(commentConfig.env).forEach(name => {
+        const env = linterContext.environments.get(name);
+
+        if (env) {
+            commentConfig = ConfigOps.merge(commentConfig, env);
+        }
+    });
     Object.assign(commentConfig.rules, commentRules);
 
     return {
@@ -801,7 +807,7 @@ module.exports = class Linter {
 
         // parse global comments and modify config
         if (allowInlineConfig !== false) {
-            const modifyConfigResult = modifyConfigsFromComments(filename, sourceCode.ast, config, this.getRules());
+            const modifyConfigResult = modifyConfigsFromComments(filename, sourceCode.ast, config, this);
 
             config = modifyConfigResult.config;
             modifyConfigResult.problems.forEach(problem => problems.push(problem));


Test patch:
diff --git a/lib/testers/rule-tester.js b/lib/testers/rule-tester.js
index 98297262b..d7e14878c 100644
--- a/lib/testers/rule-tester.js
+++ b/lib/testers/rule-tester.js
@@ -319,7 +319,7 @@ class RuleTester {
                 }
             }));
 
-            const schema = validator.getRuleOptionsSchema(rule);
+            const schema = validator.getRuleOptionsSchema(ruleName, linter.rules);
 
             if (schema) {
                 ajv.validateSchema(schema);
@@ -335,7 +335,7 @@ class RuleTester {
                 }
             }
 
-            validator.validate(config, "rule-tester", linter.getRules(), new Environments());
+            validator.validate(config, "rule-tester", linter.rules, new Environments());
 
             /*
              * Setup AST getters.
diff --git a/tests/lib/config/config-validator.js b/tests/lib/config/config-validator.js
index 467035d97..c6fec97ae 100644
--- a/tests/lib/config/config-validator.js
+++ b/tests/lib/config/config-validator.js
@@ -98,7 +98,7 @@ describe("Validator", () => {
     describe("validate", () => {
 
         it("should do nothing with an empty config", () => {
-            const fn = validator.validate.bind(null, {}, "tests", linter.getRules(), linter.environments);
+            const fn = validator.validate.bind(null, {}, "tests", linter.rules, linter.environments);
 
             assert.doesNotThrow(fn);
         });
@@ -118,7 +118,7 @@ describe("Validator", () => {
                     rules: {}
                 },
                 "tests",
-                linter.getRules(),
+                linter.rules,
                 linter.environments
             );
 
@@ -132,7 +132,7 @@ describe("Validator", () => {
                     foo: true
                 },
                 "tests",
-                linter.getRules(),
+                linter.rules,
                 linter.environments
             );
 
@@ -141,13 +141,13 @@ describe("Validator", () => {
 
         describe("root", () => {
             it("should throw with a string value", () => {
-                const fn = validator.validate.bind(null, { root: "true" }, null, linter.getRules(), linter.environments);
+                const fn = validator.validate.bind(null, { root: "true" }, null, linter.rules, linter.environments);
 
                 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, linter.getRules(), linter.environments);
+                const fn = validator.validate.bind(null, { root: 0 }, null, linter.rules, linter.environments);
 
                 assert.throws(fn, "Property \"root\" is the wrong type (expected boolean but got `0`).");
             });
@@ -155,13 +155,13 @@ describe("Validator", () => {
 
         describe("globals", () => {
             it("should throw with a string value", () => {
-                const fn = validator.validate.bind(null, { globals: "jQuery" }, null, linter.getRules(), linter.environments);
+                const fn = validator.validate.bind(null, { globals: "jQuery" }, null, linter.rules, linter.environments);
 
                 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, linter.getRules(), linter.environments);
+                const fn = validator.validate.bind(null, { globals: ["jQuery"] }, null, linter.rules, linter.environments);
 
                 assert.throws(fn, "Property \"globals\" is the wrong type (expected object but got `[\"jQuery\"]`).");
             });
@@ -169,7 +169,7 @@ describe("Validator", () => {
 
         describe("parser", () => {
             it("should not throw with a null value", () => {
-                const fn = validator.validate.bind(null, { parser: null }, null, linter.getRules(), linter.environments);
+                const fn = validator.validate.bind(null, { parser: null }, null, linter.rules, linter.environments);
 
                 assert.doesNotThrow(fn);
             });
@@ -178,31 +178,31 @@ describe("Validator", () => {
         describe("env", () => {
 
             it("should throw with an array environment", () => {
-                const fn = validator.validate.bind(null, { env: [] }, null, linter.getRules(), linter.environments);
+                const fn = validator.validate.bind(null, { env: [] }, null, linter.rules, linter.environments);
 
                 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, linter.getRules(), linter.environments);
+                const fn = validator.validate.bind(null, { env: 1 }, null, linter.rules, linter.environments);
 
                 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, linter.getRules(), linter.environments);
+                const fn = validator.validate.bind(null, { env: { browser: true, invalid: true } }, null, linter.rules, linter.environments);
 
                 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, linter.getRules(), linter.environments);
+                const fn = validator.validate.bind(null, { env: { browser: true, invalid: false } }, null, linter.rules, linter.environments);
 
                 assert.throws(fn, "Environment key \"invalid\" is unknown\n");
             });
 
             it("should do nothing with an undefined environment", () => {
-                const fn = validator.validate.bind(null, {}, null, linter.getRules(), linter.environments);
+                const fn = validator.validate.bind(null, {}, null, linter.rules, linter.environments);
 
                 assert.doesNotThrow(fn);
             });
@@ -211,13 +211,13 @@ describe("Validator", () => {
 
         describe("plugins", () => {
             it("should not throw with an empty array", () => {
-                const fn = validator.validate.bind(null, { plugins: [] }, null, linter.getRules(), linter.environments);
+                const fn = validator.validate.bind(null, { plugins: [] }, null, linter.rules, linter.environments);
 
                 assert.doesNotThrow(fn);
             });
 
             it("should throw with a string", () => {
-                const fn = validator.validate.bind(null, { plugins: "react" }, null, linter.getRules(), linter.environments);
+                const fn = validator.validate.bind(null, { plugins: "react" }, null, linter.rules, linter.environments);
 
                 assert.throws(fn, "Property \"plugins\" is the wrong type (expected array but got `\"react\"`).");
             });
@@ -225,13 +225,13 @@ describe("Validator", () => {
 
         describe("settings", () => {
             it("should not throw with an empty object", () => {
-                const fn = validator.validate.bind(null, { settings: {} }, null, linter.getRules(), linter.environments);
+                const fn = validator.validate.bind(null, { settings: {} }, null, linter.rules, linter.environments);
 
                 assert.doesNotThrow(fn);
             });
 
             it("should throw with an array", () => {
-                const fn = validator.validate.bind(null, { settings: ["foo"] }, null, linter.getRules(), linter.environments);
+                const fn = validator.validate.bind(null, { settings: ["foo"] }, null, linter.rules, linter.environments);
 
                 assert.throws(fn, "Property \"settings\" is the wrong type (expected object but got `[\"foo\"]`).");
             });
@@ -239,19 +239,19 @@ describe("Validator", () => {
 
         describe("extends", () => {
             it("should not throw with an empty array", () => {
-                const fn = validator.validate.bind(null, { extends: [] }, null, linter.getRules(), linter.environments);
+                const fn = validator.validate.bind(null, { extends: [] }, null, linter.rules, linter.environments);
 
                 assert.doesNotThrow(fn);
             });
 
             it("should not throw with a string", () => {
-                const fn = validator.validate.bind(null, { extends: "react" }, null, linter.getRules(), linter.environments);
+                const fn = validator.validate.bind(null, { extends: "react" }, null, linter.rules, linter.environments);
 
                 assert.doesNotThrow(fn);
             });
 
             it("should throw with an object", () => {
-                const fn = validator.validate.bind(null, { extends: {} }, null, linter.getRules(), linter.environments);
+                const fn = validator.validate.bind(null, { extends: {} }, null, linter.rules, linter.environments);
 
                 assert.throws(fn, "Property \"extends\" is the wrong type (expected string/array but got `{}`).");
             });
@@ -259,13 +259,13 @@ describe("Validator", () => {
 
         describe("parserOptions", () => {
             it("should not throw with an empty object", () => {
-                const fn = validator.validate.bind(null, { parserOptions: {} }, null, linter.getRules(), linter.environments);
+                const fn = validator.validate.bind(null, { parserOptions: {} }, null, linter.rules, linter.environments);
 
                 assert.doesNotThrow(fn);
             });
 
             it("should throw with an array", () => {
-                const fn = validator.validate.bind(null, { parserOptions: ["foo"] }, null, linter.getRules(), linter.environments);
+                const fn = validator.validate.bind(null, { parserOptions: ["foo"] }, null, linter.rules, linter.environments);
 
                 assert.throws(fn, "Property \"parserOptions\" is the wrong type (expected object but got `[\"foo\"]`).");
             });
@@ -274,67 +274,67 @@ describe("Validator", () => {
         describe("rules", () => {
 
             it("should do nothing with an empty rules object", () => {
-                const fn = validator.validate.bind(null, { rules: {} }, "tests", linter.getRules(), linter.environments);
+                const fn = validator.validate.bind(null, { rules: {} }, "tests", linter.rules, linter.environments);
 
                 assert.doesNotThrow(fn);
             });
 
             it("should do nothing with a valid config with rules", () => {
-                const fn = validator.validate.bind(null, { rules: { "mock-rule": [2, "second"] } }, "tests", linter.getRules(), linter.environments);
+                const fn = validator.validate.bind(null, { rules: { "mock-rule": [2, "second"] } }, "tests", linter.rules, linter.environments);
 
                 assert.doesNotThrow(fn);
             });
 
             it("should do nothing with a valid config when severity is off", () => {
-                const fn = validator.validate.bind(null, { rules: { "mock-rule": ["off", "second"] } }, "tests", linter.getRules(), linter.environments);
+                const fn = validator.validate.bind(null, { rules: { "mock-rule": ["off", "second"] } }, "tests", linter.rules, linter.environments);
 
                 assert.doesNotThrow(fn);
             });
 
             it("should do nothing with an invalid config when severity is off", () => {
-                const fn = validator.validate.bind(null, { rules: { "mock-required-options-rule": "off" } }, "tests", linter.getRules(), linter.environments);
+                const fn = validator.validate.bind(null, { rules: { "mock-required-options-rule": "off" } }, "tests", linter.rules, linter.environments);
 
                 assert.doesNotThrow(fn);
             });
 
             it("should do nothing with an invalid config when severity is an array with 'off'", () => {
-                const fn = validator.validate.bind(null, { rules: { "mock-required-options-rule": ["off"] } }, "tests", linter.getRules(), linter.environments);
+                const fn = validator.validate.bind(null, { rules: { "mock-required-options-rule": ["off"] } }, "tests", linter.rules, linter.environments);
 
                 assert.doesNotThrow(fn);
             });
 
             it("should do nothing with a valid config when severity is warn", () => {
-                const fn = validator.validate.bind(null, { rules: { "mock-rule": ["warn", "second"] } }, "tests", linter.getRules(), linter.environments);
+                const fn = validator.validate.bind(null, { rules: { "mock-rule": ["warn", "second"] } }, "tests", linter.rules, linter.environments);
 
                 assert.doesNotThrow(fn);
             });
 
             it("should do nothing with a valid config when severity is error", () => {
-                const fn = validator.validate.bind(null, { rules: { "mock-rule": ["error", "second"] } }, "tests", linter.getRules(), linter.environments);
+                const fn = validator.validate.bind(null, { rules: { "mock-rule": ["error", "second"] } }, "tests", linter.rules, linter.environments);
 
                 assert.doesNotThrow(fn);
             });
 
             it("should do nothing with a valid config when severity is Off", () => {
-                const fn = validator.validate.bind(null, { rules: { "mock-rule": ["Off", "second"] } }, "tests", linter.getRules(), linter.environments);
+                const fn = validator.validate.bind(null, { rules: { "mock-rule": ["Off", "second"] } }, "tests", linter.rules, linter.environments);
 
                 assert.doesNotThrow(fn);
             });
 
             it("should do nothing with a valid config when severity is Warn", () => {
-                const fn = validator.validate.bind(null, { rules: { "mock-rule": ["Warn", "second"] } }, "tests", linter.getRules(), linter.environments);
+                const fn = validator.validate.bind(null, { rules: { "mock-rule": ["Warn", "second"] } }, "tests", linter.rules, linter.environments);
 
                 assert.doesNotThrow(fn);
             });
 
             it("should do nothing with a valid config when severity is Error", () => {
-                const fn = validator.validate.bind(null, { rules: { "mock-rule": ["Error", "second"] } }, "tests", linter.getRules(), linter.environments);
+                const fn = validator.validate.bind(null, { rules: { "mock-rule": ["Error", "second"] } }, "tests", linter.rules, linter.environments);
 
                 assert.doesNotThrow(fn);
             });
 
             it("should catch invalid rule options", () => {
-                const fn = validator.validate.bind(null, { rules: { "mock-rule": [3, "third"] } }, "tests", linter.getRules(), linter.environments);
+                const fn = validator.validate.bind(null, { rules: { "mock-rule": [3, "third"] } }, "tests", linter.rules, linter.environments);
 
                 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");
             });
@@ -342,7 +342,7 @@ describe("Validator", () => {
             it("should allow for rules with no options", () => {
                 linter.defineRule("mock-no-options-rule", mockNoOptionsRule);
 
-                const fn = validator.validate.bind(null, { rules: { "mock-no-options-rule": 2 } }, "tests", linter.getRules(), linter.environments);
+                const fn = validator.validate.bind(null, { rules: { "mock-no-options-rule": 2 } }, "tests", linter.rules, linter.environments);
 
                 assert.doesNotThrow(fn);
             });
@@ -350,7 +350,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, { rules: { "mock-no-options-rule": [2, "extra"] } }, "tests", linter.getRules(), linter.environments);
+                const fn = validator.validate.bind(null, { rules: { "mock-no-options-rule": [2, "extra"] } }, "tests", linter.rules, linter.environments);
 
                 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");
             });
@@ -358,43 +358,43 @@ describe("Validator", () => {
 
         describe("overrides", () => {
             it("should not throw with an empty overrides array", () => {
-                const fn = validator.validate.bind(null, { overrides: [] }, "tests", linter.getRules(), linter.environments);
+                const fn = validator.validate.bind(null, { overrides: [] }, "tests", linter.rules, linter.environments);
 
                 assert.doesNotThrow(fn);
             });
 
             it("should not throw with a valid overrides array", () => {
-                const fn = validator.validate.bind(null, { overrides: [{ files: "*", rules: {} }] }, "tests", linter.getRules(), linter.environments);
+                const fn = validator.validate.bind(null, { overrides: [{ files: "*", rules: {} }] }, "tests", linter.rules, linter.environments);
 
                 assert.doesNotThrow(fn);
             });
 
             it("should throw if override does not specify files", () => {
-                const fn = validator.validate.bind(null, { overrides: [{ rules: {} }] }, "tests", linter.getRules(), linter.environments);
+                const fn = validator.validate.bind(null, { overrides: [{ rules: {} }] }, "tests", linter.rules, linter.environments);
 
                 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", linter.getRules(), linter.environments);
+                const fn = validator.validate.bind(null, { overrides: [{ files: [] }] }, "tests", linter.rules, linter.environments);
 
                 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 less 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", linter.getRules(), linter.environments);
+                const fn = validator.validate.bind(null, { overrides: [{ files: "*", overrides: [{ files: "*", rules: {} }] }] }, "tests", linter.rules, linter.environments);
 
                 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", linter.getRules(), linter.environments);
+                const fn = validator.validate.bind(null, { overrides: [{ files: "*", extends: "eslint-recommended" }] }, "tests", linter.rules, linter.environments);
 
                 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", linter.getRules(), linter.environments);
+                const fn = validator.validate.bind(null, { overrides: [{ files: "*", root: "true" }] }, "tests", linter.rules, linter.environments);
 
                 assert.throws(fn, "ESLint configuration in tests is invalid:\n\t- Unexpected top-level property \"overrides[0].root\".\n");
             });
@@ -405,12 +405,12 @@ describe("Validator", () => {
     describe("getRuleOptionsSchema", () => {
 
         it("should return null for a missing rule", () => {
-            assert.equal(validator.getRuleOptionsSchema(linter.rules.get("non-existent-rule")), null);
+            assert.equal(validator.getRuleOptionsSchema("non-existent-rule", linter.rules), null);
         });
 
         it("should not modify object schema", () => {
             linter.defineRule("mock-object-rule", mockObjectRule);
-            assert.deepEqual(validator.getRuleOptionsSchema(linter.rules.get("mock-object-rule")), {
+            assert.deepEqual(validator.getRuleOptionsSchema("mock-object-rule", linter.rules), {
                 enum: ["first", "second"]
             });
         });
@@ -420,43 +420,43 @@ describe("Validator", () => {
     describe("validateRuleOptions", () => {
 
         it("should throw for incorrect warning level number", () => {
-            const fn = validator.validateRuleOptions.bind(null, linter.rules.get("mock-rule"), "mock-rule", 3, "tests");
+            const fn = validator.validateRuleOptions.bind(null, "mock-rule", 3, "tests", linter.rules);
 
             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");
         });
 
         it("should throw for incorrect warning level string", () => {
-            const fn = validator.validateRuleOptions.bind(null, linter.rules.get("mock-rule"), "mock-rule", "booya", "tests");
+            const fn = validator.validateRuleOptions.bind(null, "mock-rule", "booya", "tests", linter.rules);
 
             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 '\"booya\"').\n");
         });
 
         it("should throw for invalid-type warning level", () => {
-            const fn = validator.validateRuleOptions.bind(null, linter.rules.get("mock-rule"), "mock-rule", [["error"]], "tests");
+            const fn = validator.validateRuleOptions.bind(null, "mock-rule", [["error"]], "tests", linter.rules);
 
             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 '[ \"error\" ]').\n");
         });
 
         it("should only check warning level for nonexistent rules", () => {
-            const fn = validator.validateRuleOptions.bind(null, linter.rules.get("non-existent-rule"), "non-existent-rule", [3, "foobar"], "tests");
+            const fn = validator.validateRuleOptions.bind(null, "non-existent-rule", [3, "foobar"], "tests", linter.rules);
 
             assert.throws(fn, "tests:\n\tConfiguration for rule \"non-existent-rule\" is invalid:\n\tSeverity should be one of the following: 0 = off, 1 = warn, 2 = error (you passed '3').\n");
         });
 
         it("should only check warning level for plugin rules", () => {
-            const fn = validator.validateRuleOptions.bind(null, linter.rules.get("plugin/rule"), "plugin/rule", 3, "tests");
+            const fn = validator.validateRuleOptions.bind(null, "plugin/rule", 3, "tests", linter.rules);
 
             assert.throws(fn, "tests:\n\tConfiguration for rule \"plugin/rule\" is invalid:\n\tSeverity should be one of the following: 0 = off, 1 = warn, 2 = error (you passed '3').\n");
         });
 
         it("should throw for incorrect configuration values", () => {
-            const fn = validator.validateRuleOptions.bind(null, linter.rules.get("mock-rule"), "mock-rule", [2, "frist"], "tests");
+            const fn = validator.validateRuleOptions.bind(null, "mock-rule", [2, "frist"], "tests", linter.rules);
 
             assert.throws(fn, "tests:\n\tConfiguration for rule \"mock-rule\" is invalid:\n\tValue \"frist\" should be equal to one of the allowed values.\n");
         });
 
         it("should throw for too many configuration values", () => {
-            const fn = validator.validateRuleOptions.bind(null, linter.rules.get("mock-rule"), "mock-rule", [2, "first", "second"], "tests");
+            const fn = validator.validateRuleOptions.bind(null, "mock-rule", [2, "first", "second"], "tests", linter.rules);
 
             assert.throws(fn, "tests:\n\tConfiguration for rule \"mock-rule\" is invalid:\n\tValue \"first,second\" should NOT have more than 1 items.\n");
         });