Repository: eslint/eslint
Pull request #9219 (2017-09-03 06:11:20)

Chore: remove currentFilename prop from Linter instances (refs #9161)
<!--
    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] 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 (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 removes the undocumented `currentFilename` property from `Linter` instances.

This relies on https://github.com/eslint/eslint/pull/9218. The tests will pass after https://github.com/eslint/eslint/pull/9218 is merged.

**Is there anything you'd like reviewers to focus on?**

Nothing in particular


eslintbot: LGTM
not-an-aardvark: ¯\\\_(ツ)_/¯ I'm fine with it because we have the ["use at your own risk"](https://eslint.org/docs/developer-guide/nodejs-api) warning for undocumented APIs.
platinumazure: Possible compromise: Could we consider this an Update rather than a Chore and make it semver-minor?
eslintbot: LGTM
not-an-aardvark: I'm fine with including this in a semver-minor release as a compromise, although I don't see how it would end up there based on our semver policy. To me, it seems like one of the following is true:

1. There are integration developers ignoring the "use at your own risk" warning, and we're willing to accomodate them to avoid breaking builds, so we consider it a breaking change, or:
1. (1) isn't true, so this is just an internal refactor, which is semver-patch.

Basically, I don't see how this fits under `Update:` in either case.

Patch:
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 3826c28e8..363148738 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -17,7 +17,7 @@ Before filing an issue, please be sure to read the guidelines for what you're re
 
 ## Contributing Code
 
-Please sign our [Contributor License Agreement](https://js.foundation/CLA) and read over the [Pull Request Guidelines](http://eslint.org/docs/developer-guide/contributing/pull-requests).
+Please sign our [Contributor License Agreement](https://cla.js.foundation/eslint/eslint) and read over the [Pull Request Guidelines](http://eslint.org/docs/developer-guide/contributing/pull-requests).
 
 ## Full Documentation
 
diff --git a/docs/developer-guide/contributing/README.md b/docs/developer-guide/contributing/README.md
index 384e5b9e4..9321a9523 100644
--- a/docs/developer-guide/contributing/README.md
+++ b/docs/developer-guide/contributing/README.md
@@ -10,7 +10,7 @@ ESLint welcomes contributions from everyone and adheres to the [JS Foundation Co
 
 ## [Signing the CLA](https://contribute.jquery.org/cla)
 
-In order to submit code or documentation to an ESLint project, please electronically sign the [Contributor License Agreement](https://contribute.jquery.org/cla). The CLA is you giving us permission to use your contribution.
+In order to submit code or documentation to an ESLint project, you will need to electronically sign our [Contributor License Agreement](https://cla.js.foundation/eslint/eslint). The CLA is you giving us permission to use your contribution.
 
 ## [Bug Reporting](reporting-bugs)
 
diff --git a/lib/config/config-ops.js b/lib/config/config-ops.js
index d169e60dc..4ed5ec6b0 100644
--- a/lib/config/config-ops.js
+++ b/lib/config/config-ops.js
@@ -193,25 +193,25 @@ module.exports = {
     },
 
     /**
-     * Converts new-style severity settings (off, warn, error) into old-style
-     * severity settings (0, 1, 2) for all rules. Assumption is that severity
-     * values have already been validated as correct.
-     * @param {Object} config The config object to normalize.
-     * @returns {void}
+     * Normalizes the severity value of a rule's configuration to a number
+     * @param {(number|string|[number, ...*]|[string, ...*])} ruleConfig A rule's configuration value, generally
+     * received from the user. A valid config value is either 0, 1, 2, the string "off" (treated the same as 0),
+     * the string "warn" (treated the same as 1), the string "error" (treated the same as 2), or an array
+     * whose first element is one of the above values. Strings are matched case-insensitively.
+     * @returns {(0|1|2)} The numeric severity value if the config value was valid, otherwise 0.
      */
-    normalize(config) {
+    getRuleSeverity(ruleConfig) {
+        const severityValue = Array.isArray(ruleConfig) ? ruleConfig[0] : ruleConfig;
 
-        if (config.rules) {
-            Object.keys(config.rules).forEach(ruleId => {
-                const ruleConfig = config.rules[ruleId];
+        if (severityValue === 0 || severityValue === 1 || severityValue === 2) {
+            return severityValue;
+        }
 
-                if (typeof ruleConfig === "string") {
-                    config.rules[ruleId] = RULE_SEVERITY[ruleConfig.toLowerCase()] || 0;
-                } else if (Array.isArray(ruleConfig) && typeof ruleConfig[0] === "string") {
-                    ruleConfig[0] = RULE_SEVERITY[ruleConfig[0].toLowerCase()] || 0;
-                }
-            });
+        if (typeof severityValue === "string") {
+            return RULE_SEVERITY[severityValue.toLowerCase()] || 0;
         }
+
+        return 0;
     },
 
     /**
diff --git a/lib/linter.js b/lib/linter.js
index 5011577f7..a52606c22 100755
--- a/lib/linter.js
+++ b/lib/linter.js
@@ -604,16 +604,6 @@ function stripUnicodeBOM(text) {
     return text;
 }
 
-/**
- * Get the severity level of a rule (0 - none, 1 - warning, 2 - error)
- * Returns 0 if the rule config is not valid (an Array or a number)
- * @param {Array|number} ruleConfig rule configuration
- * @returns {number} 0, 1, or 2, indicating rule severity
- */
-function getRuleSeverity(ruleConfig) {
-    return Array.isArray(ruleConfig) ? ruleConfig[0] : ruleConfig;
-}
-
 /**
  * Get the options for a rule (not including severity), if any
  * @param {Array|number} ruleConfig rule configuration
@@ -763,7 +753,6 @@ class Linter {
     constructor() {
         this.currentConfig = null;
         this.scopeManager = null;
-        this.currentFilename = null;
         this.traverser = null;
         this.reportingConfig = [];
         this.sourceCode = null;
@@ -822,15 +811,19 @@ class Linter {
             text = this.sourceCode.text;
         }
 
+        let providedFilename;
+
         // evaluate arguments
         if (typeof filenameOrOptions === "object") {
-            this.currentFilename = filenameOrOptions.filename;
+            providedFilename = filenameOrOptions.filename;
             allowInlineConfig = filenameOrOptions.allowInlineConfig;
             saveState = filenameOrOptions.saveState;
         } else {
-            this.currentFilename = filenameOrOptions;
+            providedFilename = filenameOrOptions;
         }
 
+        const filename = typeof providedFilename === "string" ? providedFilename : "<input>";
+
         if (!saveState) {
             this.reset();
         }
@@ -865,7 +858,7 @@ class Linter {
                 stripUnicodeBOM(text).replace(astUtils.SHEBANG_MATCHER, (match, captured) => `//${captured}`),
                 config.parserOptions,
                 config.parser,
-                this.currentFilename
+                filename
             );
 
             if (!parseResult.success) {
@@ -880,15 +873,12 @@ class Linter {
 
         // parse global comments and modify config
         if (allowInlineConfig !== false) {
-            const modifyConfigResult = modifyConfigsFromComments(this.currentFilename, this.sourceCode.ast, config, this);
+            const modifyConfigResult = modifyConfigsFromComments(filename, this.sourceCode.ast, config, this);
 
             config = modifyConfigResult.config;
             modifyConfigResult.problems.forEach(problem => problems.push(problem));
         }
 
-        // ensure that severities are normalized in the config
-        ConfigOps.normalize(config);
-
         const emitter = new EventEmitter().setMaxListeners(Infinity);
 
         /*
@@ -900,9 +890,9 @@ class Linter {
             Object.assign(
                 Object.create(BASE_TRAVERSAL_CONTEXT),
                 {
-                    getAncestors: this.getAncestors.bind(this),
+                    getAncestors: () => this.traverser.parents(),
                     getDeclaredVariables: this.getDeclaredVariables.bind(this),
-                    getFilename: this.getFilename.bind(this),
+                    getFilename: () => filename,
                     getScope: this.getScope.bind(this),
                     getSourceCode: () => this.sourceCode,
                     markVariableAsUsed: this.markVariableAsUsed.bind(this),
@@ -928,7 +918,12 @@ class Linter {
         );
 
         // enable appropriate rules
-        Object.keys(config.rules).filter(ruleId => getRuleSeverity(config.rules[ruleId]) > 0).forEach(ruleId => {
+        Object.keys(config.rules).forEach(ruleId => {
+            const severity = ConfigOps.getRuleSeverity(config.rules[ruleId]);
+
+            if (severity === 0) {
+                return;
+            }
             let ruleCreator = this.rules.get(ruleId);
 
             if (!ruleCreator) {
@@ -942,7 +937,6 @@ class Linter {
                 this.rules.define(ruleId, ruleCreator);
             }
 
-            const severity = getRuleSeverity(config.rules[ruleId]);
             const ruleContext = Object.freeze(
                 Object.assign(
                     Object.create(sharedTraversalContext),
@@ -1050,14 +1044,6 @@ class Linter {
         return this.sourceCode;
     }
 
-    /**
-     * Gets nodes that are ancestors of current node.
-     * @returns {ASTNode[]} Array of objects representing ancestors.
-     */
-    getAncestors() {
-        return this.traverser.parents();
-    }
-
     /**
      * Gets the scope for the current node.
      * @returns {Object} An object representing the current node's scope.
@@ -1134,19 +1120,6 @@ class Linter {
         return false;
     }
 
-    /**
-     * Gets the filename for the currently parsed source.
-     * @returns {string} The filename associated with the source being parsed.
-     *     Defaults to "<input>" if no filename info is present.
-     */
-    getFilename() {
-        if (typeof this.currentFilename === "string") {
-            return this.currentFilename;
-        }
-        return "<input>";
-
-    }
-
     /**
      * Defines a new linting rule.
      * @param {string} ruleId A unique rule identifier


Test patch:
diff --git a/tests/lib/config/config-ops.js b/tests/lib/config/config-ops.js
index ed95238d0..faaff37f1 100644
--- a/tests/lib/config/config-ops.js
+++ b/tests/lib/config/config-ops.js
@@ -10,6 +10,7 @@
 
 const assert = require("chai").assert,
     leche = require("leche"),
+    util = require("util"),
     environments = require("../../../conf/environments"),
     Environments = require("../../../lib/config/environments"),
     ConfigCache = require("../../../lib/config/config-cache"),
@@ -550,150 +551,36 @@ describe("ConfigOps", () => {
         });
     });
 
-    describe("normalize()", () => {
-        it("should convert error rule setting to 2 when rule has just a severity", () => {
-            const config = {
-                rules: {
-                    foo: "errOr",
-                    bar: "error"
-                }
-            };
-
-            ConfigOps.normalize(config);
-
-            assert.deepEqual(config, {
-                rules: {
-                    foo: 2,
-                    bar: 2
-                }
-            });
-        });
-
-        it("should convert error rule setting to 2 when rule has array with severity", () => {
-            const config = {
-                rules: {
-                    foo: ["Error", "something"],
-                    bar: "error"
-                }
-            };
-
-            ConfigOps.normalize(config);
-
-            assert.deepEqual(config, {
-                rules: {
-                    foo: [2, "something"],
-                    bar: 2
-                }
-            });
-        });
-
-        it("should convert warn rule setting to 1 when rule has just a severity", () => {
-            const config = {
-                rules: {
-                    foo: "waRn",
-                    bar: "warn"
-                }
-            };
-
-            ConfigOps.normalize(config);
-
-            assert.deepEqual(config, {
-                rules: {
-                    foo: 1,
-                    bar: 1
-                }
-            });
-        });
-
-        it("should convert warn rule setting to 1 when rule has array with severity", () => {
-            const config = {
-                rules: {
-                    foo: ["Warn", "something"],
-                    bar: "warn"
-                }
-            };
-
-            ConfigOps.normalize(config);
-
-            assert.deepEqual(config, {
-                rules: {
-                    foo: [1, "something"],
-                    bar: 1
-                }
-            });
-        });
-
-        it("should convert off rule setting to 0 when rule has just a severity", () => {
-            const config = {
-                rules: {
-                    foo: "ofF",
-                    bar: "off"
-                }
-            };
-
-            ConfigOps.normalize(config);
-
-            assert.deepEqual(config, {
-                rules: {
-                    foo: 0,
-                    bar: 0
-                }
-            });
-        });
-
-        it("should convert off rule setting to 0 when rule has array with severity", () => {
-            const config = {
-                rules: {
-                    foo: ["Off", "something"],
-                    bar: "off"
-                }
-            };
-
-            ConfigOps.normalize(config);
-
-            assert.deepEqual(config, {
-                rules: {
-                    foo: [0, "something"],
-                    bar: 0
-                }
-            });
-        });
-
-        it("should convert invalid rule setting to 0 when rule has just a severity", () => {
-            const config = {
-                rules: {
-                    foo: "invalid",
-                    bar: "invalid"
-                }
-            };
-
-            ConfigOps.normalize(config);
-
-            assert.deepEqual(config, {
-                rules: {
-                    foo: 0,
-                    bar: 0
-                }
-            });
-        });
-
-        it("should convert invalid rule setting to 0 when rule has array with severity", () => {
-            const config = {
-                rules: {
-                    foo: ["invalid", "something"],
-                    bar: "invalid"
-                }
-            };
-
-            ConfigOps.normalize(config);
-
-            assert.deepEqual(config, {
-                rules: {
-                    foo: [0, "something"],
-                    bar: 0
-                }
-            });
-        });
+    describe("getRuleSeverity()", () => {
+        const EXPECTED_RESULTS = new Map([
+            [0, 0],
+            [1, 1],
+            [2, 2],
+            [[0], 0],
+            [[1], 1],
+            [[2], 2],
+            ["off", 0],
+            ["warn", 1],
+            ["error", 2],
+            [["off"], 0],
+            [["warn"], 1],
+            [["error"], 2],
+            ["OFF", 0],
+            ["wArN", 1],
+            [["ErRoR"], 2],
+            ["invalid config", 0],
+            [["invalid config"], 0],
+            [3, 0],
+            [[3], 0],
+            [1.5, 0],
+            [[1.5], 0]
+        ]);
+
+        for (const key of EXPECTED_RESULTS.keys()) {
+            it(`returns ${util.inspect(EXPECTED_RESULTS.get(key))} for ${util.inspect(key)}`, () => {
+                assert.strictEqual(ConfigOps.getRuleSeverity(key), EXPECTED_RESULTS.get(key));
+            });
+        }
     });
 
     describe("normalizeToStrings()", () => {
diff --git a/tests/lib/linter.js b/tests/lib/linter.js
index 900e02d51..92d7fa8c7 100644
--- a/tests/lib/linter.js
+++ b/tests/lib/linter.js
@@ -302,36 +302,43 @@ describe("Linter", () => {
 
     });
 
-    describe("when calling getAncestors", () => {
+    describe("when calling context.getAncestors", () => {
         const code = TEST_CODE;
 
         it("should retrieve all ancestors when used", () => {
 
             const config = { rules: { checker: "error" } };
-            const spy = sandbox.spy(() => {
-                const ancestors = linter.getAncestors();
+            let spy;
 
-                assert.equal(ancestors.length, 3);
-            });
+            linter.defineRule("checker", context => {
+                spy = sandbox.spy(() => {
+                    const ancestors = context.getAncestors();
 
-            linter.defineRule("checker", () => ({ BinaryExpression: spy }));
+                    assert.equal(ancestors.length, 3);
+                });
+                return { BinaryExpression: spy };
+            });
 
             linter.verify(code, config, filename, true);
-            assert(spy.calledOnce);
+            assert(spy && spy.calledOnce);
         });
 
         it("should retrieve empty ancestors for root node", () => {
             const config = { rules: { checker: "error" } };
-            const spy = sandbox.spy(() => {
-                const ancestors = linter.getAncestors();
+            let spy;
 
-                assert.equal(ancestors.length, 0);
-            });
+            linter.defineRule("checker", context => {
+                spy = sandbox.spy(() => {
+                    const ancestors = context.getAncestors();
 
-            linter.defineRule("checker", () => ({ Program: spy }));
+                    assert.equal(ancestors.length, 0);
+                });
+
+                return { Program: spy };
+            });
 
             linter.verify(code, config);
-            assert(spy.calledOnce);
+            assert(spy && spy.calledOnce);
         });
     });