Repository: eslint/eslint
Pull request #11341 (2019-02-01 00:53:30)

Update: no-shadow-restricted-names lets unassigned vars shadow undefined
<!--
    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] Changes an existing rule

**What rule do you want to change?**

[`no-shadow-restricted-names`](https://eslint.org/docs/rules/no-shadow-restricted-names)

**Does this change cause the rule to produce more or fewer warnings?**

Fewer

**How will the change be implemented? (New option, new default behavior, etc.)?**

New default behavior

**Please provide some example code that this change will affect:**

```js
{ let undefined; }
{ let undefined = 5; }
```

**What does the rule currently do for this code?**

It reports an error on both lines.

**What will the rule do after it's changed?**

It will not report an error on the first line, but it will continue reporting an error on the second line.

**What changes did you make? (Give an overview)**

This updates the `no-shadow-restricted-names` to allow a variable to shadow `undefined` if that variable is never assigned a value (i.e. if the variable always actually has a value of `undefined`). The declaration `var undefined;` is occasionally used in pre-ES5 environments where the `undefined` global is mutable, to ensure that the identifier `undefined` can reliably be used even if someone else tampered with the global. In general, a `var undefined;` declaration doesn't really violate the spirit of the rule, because it doesn't change the value of the identifier `undefined`.

The goal of this change is to eliminate a false positive for codebases that support pre-ES5 environments, so that the rule can be added to `eslint:recommended` in the future.

**Is there anything you'd like reviewers to focus on?**

Nothing in particular



Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0da896543..acbd83a2d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,17 @@
+v5.13.0 - February 1, 2019
+
+* [`91c8884`](https://github.com/eslint/eslint/commit/91c8884971f5e57f5f7490d8daf92c4a9a489836) Chore: use local function to append "s" instead of a package (#11293) (Timo Tijhof)
+* [`b5143bf`](https://github.com/eslint/eslint/commit/b5143bfc09e53d8da8f63421ade093b7593f4f51) Update: for-direction detection false positives/negatives (#11254) (Ruben Bridgewater)
+* [`9005e63`](https://github.com/eslint/eslint/commit/9005e632d13476880c55f7e3c8a6e450762a5171) Chore: increase camelcase test coverage (#11299) (Redmond Tran)
+* [`5b14ad1`](https://github.com/eslint/eslint/commit/5b14ad1003c7df9a37621dea55c6d6d0484adc05) Fix: false positive in no-constant-condition (fixes #11306) (#11308) (Pig Fang)
+* [`6567c4f`](https://github.com/eslint/eslint/commit/6567c4f6665df85c3347388b29d8193cc8208d63) Fix: only remove arrow before body in object-shorthand (fixes #11305) (#11307) (Pig Fang)
+* [`fa2f370`](https://github.com/eslint/eslint/commit/fa2f370affa4814dbdda278f9859d0172d4b7aa2) Docs: update rule configuration values in examples (#11323) (Kai Cataldo)
+* [`0a3c3ff`](https://github.com/eslint/eslint/commit/0a3c3ff1d91e8f39943efc4a7d2bf6927d68d37e) New: Allow globals to be disabled/configured with strings (fixes #9940) (#11338) (Teddy Katz)
+* [`dccee63`](https://github.com/eslint/eslint/commit/dccee63cf41234180c71bf0fe01b165c9078fc69) Chore: avoid hard-coding the list of core rules in eslint:recommended (#11336) (Teddy Katz)
+* [`c1fd6f5`](https://github.com/eslint/eslint/commit/c1fd6f54d92efe615bcae529006221e122dbe9e6) Chore: remove undocumented `Linter#rules` property (refs #9161) (#11335) (Teddy Katz)
+* [`36e3356`](https://github.com/eslint/eslint/commit/36e335681d61cbe3c83b653b7cc5f95730f1d86e) Chore: remove dead code for loading rules (#11334) (Teddy Katz)
+* [`c464e27`](https://github.com/eslint/eslint/commit/c464e2744ec76e7e9c6c5af0f6162c92187f1ece) Docs: Rename `result` -> `foo` (#11210) (Alexis Tyler)
+
 v5.12.1 - January 18, 2019
 
 * [`eb5c401`](https://github.com/eslint/eslint/commit/eb5c4014f16be1c2003ed46ce9560d0d8a567d0f) Chore: use meta.messages in some rules (2/4) (refs #9870) (#10773) (薛定谔的猫)
diff --git a/docs/rules/no-shadow-restricted-names.md b/docs/rules/no-shadow-restricted-names.md
index 0624a82aa..9dfc03719 100644
--- a/docs/rules/no-shadow-restricted-names.md
+++ b/docs/rules/no-shadow-restricted-names.md
@@ -19,7 +19,7 @@ function NaN(){}
 
 !function(Infinity){};
 
-var undefined;
+var undefined = 5;
 
 try {} catch(eval){}
 ```
@@ -32,6 +32,9 @@ Examples of **correct** code for this rule:
 var Object;
 
 function f(a, b){}
+
+// Exception: `undefined` may be shadowed if the variable is never assigned a value.
+var undefined;
 ```
 
 ## Further Reading
diff --git a/docs/rules/no-useless-call.md b/docs/rules/no-useless-call.md
index 0356c1270..196cc6df3 100644
--- a/docs/rules/no-useless-call.md
+++ b/docs/rules/no-useless-call.md
@@ -37,6 +37,7 @@ obj.foo.call(otherObj, 1, 2, 3);
 obj.foo.apply(otherObj, [1, 2, 3]);
 
 // The argument list is variadic.
+// Those are warned by the `prefer-spread` rule.
 foo.apply(undefined, args);
 foo.apply(null, args);
 obj.foo.apply(obj, args);
@@ -66,3 +67,7 @@ a[++i].foo.call(a[i], 1, 2, 3);
 ## When Not To Use It
 
 If you don't want to be notified about unnecessary `.call()` and `.apply()`, you can safely disable this rule.
+
+## Related Rules
+
+* [prefer-spread](prefer-spread.md)
diff --git a/docs/rules/one-var.md b/docs/rules/one-var.md
index c35082ede..3c964c4a4 100644
--- a/docs/rules/one-var.md
+++ b/docs/rules/one-var.md
@@ -324,7 +324,9 @@ Examples of **correct** code for this rule with the `{ separateRequires: true }`
 
 var foo = require("foo");
 var bar = "bar";
+```
 
+```js
 var foo = require("foo"),
     bar = require("bar");
 ```
diff --git a/docs/user-guide/configuring.md b/docs/user-guide/configuring.md
index 13ec086ae..1eed790a2 100644
--- a/docs/user-guide/configuring.md
+++ b/docs/user-guide/configuring.md
@@ -45,7 +45,7 @@ Here's an example `.eslintrc.json` file:
         }
     },
     "rules": {
-        "semi": 2
+        "semi": "error"
     }
 }
 ```
@@ -208,19 +208,19 @@ To specify globals using a comment inside of your JavaScript file, use the follo
 /* global var1, var2 */
 ```
 
-This defines two global variables, `var1` and `var2`. If you want to optionally specify that these global variables should never be written to (only read), then you can set each with a `false` flag:
+This defines two global variables, `var1` and `var2`. If you want to optionally specify that these global variables can be written to (rather than only being read), then you can set each with a `writeable` flag:
 
 ```js
-/* global var1:false, var2:false */
+/* global var1:writeable, var2:writeable */
 ```
 
-To configure global variables inside of a configuration file, use the `globals` key and indicate the global variables you want to use. Set each global variable name equal to `true` to allow the variable to be overwritten or `false` to disallow overwriting. For example:
+To configure global variables inside of a configuration file, set the `globals` configuration property to an object containing keys named for each of the global variables you want to use. For each global variable key, set the corresponding value equal to `"writeable"` to allow the variable to be overwritten or `"readable"` to disallow overwriting. For example:
 
 ```json
 {
     "globals": {
-        "var1": true,
-        "var2": false
+        "var1": "writeable",
+        "var2": "readable"
     }
 }
 ```
@@ -230,12 +230,27 @@ And in YAML:
 ```yaml
 ---
   globals:
-    var1: true
-    var2: false
+    var1: writeable
+    var2: readable
 ```
 
 These examples allow `var1` to be overwritten in your code, but disallow it for `var2`.
 
+Globals can be disabled with the string `"off"`. For example, in an environment where most ES2015 globals are available but `Promise` is unavailable, you might use this config:
+
+```json
+{
+    "env": {
+        "es6": true
+    },
+    "globals": {
+        "Promise": "off"
+    }
+}
+```
+
+For historical reasons, the boolean values `false` and `true` can also be used to configure globals, and are equivalent to `"readable"` and `"writeable"`, respectively. However, this usage of booleans is deprecated.
+
 **Note:** Enable the [no-global-assign](../rules/no-global-assign.md) rule to disallow modifications to read-only global variables in your code.
 
 ## Configuring Plugins
@@ -801,15 +816,15 @@ In your `.eslintrc.json`:
 ```json
 {
   "rules": {
-    "quotes": [ 2, "double" ]
+    "quotes": ["error", "double"]
   },
 
   "overrides": [
     {
-      "files": [ "bin/*.js", "lib/*.js" ],
+      "files": ["bin/*.js", "lib/*.js"],
       "excludedFiles": "*.test.js",
       "rules": {
-        "quotes": [ 2, "single" ]
+        "quotes": ["error", "single"]
       }
     }
   ]
diff --git a/lib/config/config-file.js b/lib/config/config-file.js
index dde79cb40..f76b92830 100644
--- a/lib/config/config-file.js
+++ b/lib/config/config-file.js
@@ -280,15 +280,38 @@ function writeYAMLConfigFile(config, filePath) {
  * Writes a configuration file in JavaScript format.
  * @param {Object} config The configuration object to write.
  * @param {string} filePath The filename to write to.
+ * @throws {Error} If an error occurs linting the config file contents.
  * @returns {void}
  * @private
  */
 function writeJSConfigFile(config, filePath) {
     debug(`Writing JS config file: ${filePath}`);
 
-    const content = `module.exports = ${stringify(config, { cmp: sortByKey, space: 4 })};`;
+    let contentToWrite;
+    const stringifiedContent = `module.exports = ${stringify(config, { cmp: sortByKey, space: 4 })};`;
 
-    fs.writeFileSync(filePath, content, "utf8");
+    try {
+        const CLIEngine = require("../cli-engine");
+        const linter = new CLIEngine({
+            baseConfig: config,
+            fix: true,
+            useEslintrc: false
+        });
+        const report = linter.executeOnText(stringifiedContent);
+
+        contentToWrite = report.results[0].output || stringifiedContent;
+    } catch (e) {
+        debug("Error linting JavaScript config file, writing unlinted version");
+        const errorMessage = e.message;
+
+        contentToWrite = stringifiedContent;
+        e.message = "An error occurred while generating your JavaScript config file. ";
+        e.message += "A config file was still generated, but the config file itself may not follow your linting rules.";
+        e.message += `\nError: ${errorMessage}`;
+        throw e;
+    } finally {
+        fs.writeFileSync(filePath, contentToWrite, "utf8");
+    }
 }
 
 /**
diff --git a/lib/config/config-ops.js b/lib/config/config-ops.js
index 6c298d364..48f38b490 100644
--- a/lib/config/config-ops.js
+++ b/lib/config/config-ops.js
@@ -370,5 +370,33 @@ module.exports = {
 
         return patternList.some(pattern => minimatch(filePath, pattern, opts)) &&
             !excludedPatternList.some(excludedPattern => minimatch(filePath, excludedPattern, opts));
+    },
+
+    /**
+     * Normalizes a value for a global in a config
+     * @param {(boolean|string|null)} configuredValue The value given for a global in configuration or in
+     * a global directive comment
+     * @returns {("readable"|"writeable"|"off")} The value normalized as a string
+     */
+    normalizeConfigGlobal(configuredValue) {
+        switch (configuredValue) {
+            case "off":
+                return "off";
+
+            case true:
+            case "true":
+            case "writeable":
+                return "writeable";
+
+            case null:
+            case false:
+            case "false":
+            case "readable":
+                return "readable";
+
+            // Fallback to minimize compatibility impact
+            default:
+                return "writeable";
+        }
     }
 };
diff --git a/lib/formatters/table.js b/lib/formatters/table.js
index ebc3314e7..a74cce0d5 100644
--- a/lib/formatters/table.js
+++ b/lib/formatters/table.js
@@ -9,13 +9,22 @@
 //------------------------------------------------------------------------------
 
 const chalk = require("chalk"),
-    table = require("table").table,
-    pluralize = require("pluralize");
+    table = require("table").table;
 
 //------------------------------------------------------------------------------
 // Helpers
 //------------------------------------------------------------------------------
 
+/**
+ * Given a word and a count, append an "s" if count is not one.
+ * @param {string} word A word.
+ * @param {number} count Quantity.
+ * @returns {string} The original word with an s on the end if count is not one.
+ */
+function pluralize(word, count) {
+    return (count === 1 ? word : `${word}s`);
+}
+
 /**
  * Draws text table.
  * @param {Array<Object>} messages Error messages relating to a specific file.
@@ -129,10 +138,10 @@ module.exports = function(report) {
 
     result += `\n${table([
         [
-            chalk.red(pluralize("Error", errorCount, true))
+            chalk.red(pluralize(`${errorCount} Error`, errorCount))
         ],
         [
-            chalk.yellow(pluralize("Warning", warningCount, true))
+            chalk.yellow(pluralize(`${warningCount} Warning`, warningCount))
         ]
     ], {
         columns: {
diff --git a/lib/linter.js b/lib/linter.js
index c3195cc6b..29505e9ac 100644
--- a/lib/linter.js
+++ b/lib/linter.js
@@ -70,30 +70,30 @@ const commentParser = new ConfigCommentParser();
  * @returns {void}
  */
 function addDeclaredGlobals(globalScope, configGlobals, commentDirectives) {
-    Object.keys(configGlobals).forEach(name => {
-        let variable = globalScope.set.get(name);
-
-        if (!variable) {
-            variable = new eslintScope.Variable(name, globalScope);
-            variable.eslintExplicitGlobal = false;
-            globalScope.variables.push(variable);
-            globalScope.set.set(name, variable);
-        }
-        variable.writeable = configGlobals[name];
-    });
-
-    Object.keys(commentDirectives.enabledGlobals).forEach(name => {
-        let variable = globalScope.set.get(name);
+    const mergedGlobalsInfo = Object.assign(
+        {},
+        lodash.mapValues(configGlobals, value => ({ sourceComment: null, value: ConfigOps.normalizeConfigGlobal(value) })),
+        lodash.mapValues(commentDirectives.enabledGlobals, ({ comment, value }) => ({ sourceComment: comment, value: ConfigOps.normalizeConfigGlobal(value) }))
+    );
 
-        if (!variable) {
-            variable = new eslintScope.Variable(name, globalScope);
-            variable.eslintExplicitGlobal = true;
-            variable.eslintExplicitGlobalComment = commentDirectives.enabledGlobals[name].comment;
-            globalScope.variables.push(variable);
-            globalScope.set.set(name, variable);
-        }
-        variable.writeable = commentDirectives.enabledGlobals[name].value;
-    });
+    Object.keys(mergedGlobalsInfo)
+        .filter(name => mergedGlobalsInfo[name].value !== "off")
+        .forEach(name => {
+            let variable = globalScope.set.get(name);
+
+            if (!variable) {
+                variable = new eslintScope.Variable(name, globalScope);
+                if (mergedGlobalsInfo[name].sourceComment === null) {
+                    variable.eslintExplicitGlobal = false;
+                } else {
+                    variable.eslintExplicitGlobal = true;
+                    variable.eslintExplicitGlobalComment = mergedGlobalsInfo[name].sourceComment;
+                }
+                globalScope.variables.push(variable);
+                globalScope.set.set(name, variable);
+            }
+            variable.writeable = (mergedGlobalsInfo[name].value === "writeable");
+        });
 
     // mark all exported variables as such
     Object.keys(commentDirectives.exportedVariables).forEach(name => {
@@ -191,12 +191,12 @@ function getDirectiveComments(filename, ast, ruleMapper) {
         } else if (comment.type === "Block") {
             switch (match[1]) {
                 case "exported":
-                    Object.assign(exportedVariables, commentParser.parseBooleanConfig(directiveValue, comment));
+                    Object.assign(exportedVariables, commentParser.parseStringConfig(directiveValue, comment));
                     break;
 
                 case "globals":
                 case "global":
-                    Object.assign(enabledGlobals, commentParser.parseBooleanConfig(directiveValue, comment));
+                    Object.assign(enabledGlobals, commentParser.parseStringConfig(directiveValue, comment));
                     break;
 
                 case "eslint-disable":
diff --git a/lib/rules/for-direction.js b/lib/rules/for-direction.js
index db079b267..c15d10e5f 100644
--- a/lib/rules/for-direction.js
+++ b/lib/rules/for-direction.js
@@ -42,6 +42,23 @@ module.exports = {
             });
         }
 
+        /**
+         * check the right side of the assignment
+         * @param {ASTNode} update UpdateExpression to check
+         * @param {int} dir expected direction that could either be turned around or invalidated
+         * @returns {int} return dir, the negated dir or zero if it's not clear for identifiers
+         */
+        function getRightDirection(update, dir) {
+            if (update.right.type === "UnaryExpression") {
+                if (update.right.operator === "-") {
+                    return -dir;
+                }
+            } else if (update.right.type === "Identifier") {
+                return 0;
+            }
+            return dir;
+        }
+
         /**
          * check UpdateExpression add/sub the counter
          * @param {ASTNode} update UpdateExpression to check
@@ -69,10 +86,10 @@ module.exports = {
         function getAssignmentDirection(update, counter) {
             if (update.left.name === counter) {
                 if (update.operator === "+=") {
-                    return 1;
+                    return getRightDirection(update, 1);
                 }
                 if (update.operator === "-=") {
-                    return -1;
+                    return getRightDirection(update, -1);
                 }
             }
             return 0;
@@ -85,26 +102,22 @@ module.exports = {
                     const operator = node.test.operator;
                     const update = node.update;
 
-                    if (operator === "<" || operator === "<=") {
-
-                        // report error if update sub the counter (--, -=)
-                        if (update.type === "UpdateExpression" && getUpdateDirection(update, counter) < 0) {
-                            report(node);
-                        }
+                    let wrongDirection;
 
-                        if (update.type === "AssignmentExpression" && getAssignmentDirection(update, counter) < 0) {
-                            report(node);
-                        }
+                    if (operator === "<" || operator === "<=") {
+                        wrongDirection = -1;
                     } else if (operator === ">" || operator === ">=") {
+                        wrongDirection = 1;
+                    } else {
+                        return;
+                    }
 
-                        // report error if update add the counter (++, +=)
-                        if (update.type === "UpdateExpression" && getUpdateDirection(update, counter) > 0) {
-                            report(node);
-                        }
-
-                        if (update.type === "AssignmentExpression" && getAssignmentDirection(update, counter) > 0) {
+                    if (update.type === "UpdateExpression") {
+                        if (getUpdateDirection(update, counter) === wrongDirection) {
                             report(node);
                         }
+                    } else if (update.type === "AssignmentExpression" && getAssignmentDirection(update, counter) === wrongDirection) {
+                        report(node);
                     }
                 }
             }
diff --git a/lib/rules/no-constant-condition.js b/lib/rules/no-constant-condition.js
index 39c2928ee..fb36207eb 100644
--- a/lib/rules/no-constant-condition.js
+++ b/lib/rules/no-constant-condition.js
@@ -5,6 +5,13 @@
 
 "use strict";
 
+//------------------------------------------------------------------------------
+// Helpers
+//------------------------------------------------------------------------------
+
+const EQUALITY_OPERATORS = ["===", "!==", "==", "!="];
+const RELATIONAL_OPERATORS = [">", "<", ">=", "<=", "in", "instanceof"];
+
 //------------------------------------------------------------------------------
 // Rule Definition
 //------------------------------------------------------------------------------
@@ -110,7 +117,18 @@ module.exports = {
                     const isRightShortCircuit = (isRightConstant && isLogicalIdentity(node.right, node.operator));
 
                     return (isLeftConstant && isRightConstant) ||
-                        (node.operator === "||" && isRightConstant && node.right.value) || // in the case of an "OR", we need to know if the right constant value is truthy
+                        (
+
+                            // in the case of an "OR", we need to know if the right constant value is truthy
+                            node.operator === "||" &&
+                            isRightConstant &&
+                            node.right.value &&
+                            (
+                                !node.parent ||
+                                node.parent.type !== "BinaryExpression" ||
+                                !(EQUALITY_OPERATORS.includes(node.parent.operator) || RELATIONAL_OPERATORS.includes(node.parent.operator))
+                            )
+                        ) ||
                         isLeftShortCircuit ||
                         isRightShortCircuit;
                 }
diff --git a/lib/rules/no-shadow-restricted-names.js b/lib/rules/no-shadow-restricted-names.js
index 9bdd50868..f09f3767d 100644
--- a/lib/rules/no-shadow-restricted-names.js
+++ b/lib/rules/no-shadow-restricted-names.js
@@ -4,6 +4,19 @@
  */
 "use strict";
 
+/**
+ * Determines if a variable safely shadows undefined.
+ * This is the case when a variable named `undefined` is never assigned to a value (i.e. it always shares the same value
+ * as the global).
+ * @param {eslintScope.Variable} variable The variable to check
+ * @returns {boolean} true if this variable safely shadows `undefined`
+ */
+function safelyShadowsUndefined(variable) {
+    return variable.name === "undefined" &&
+        variable.references.every(ref => !ref.isWrite()) &&
+        variable.defs.every(def => def.node.type === "VariableDeclarator" && def.node.init === null);
+}
+
 //------------------------------------------------------------------------------
 // Rule Definition
 //------------------------------------------------------------------------------
@@ -24,12 +37,13 @@ module.exports = {
 
     create(context) {
 
-        const RESTRICTED = ["undefined", "NaN", "Infinity", "arguments", "eval"];
+
+        const RESTRICTED = new Set(["undefined", "NaN", "Infinity", "arguments", "eval"]);
 
         return {
             "VariableDeclaration, :function, CatchClause"(node) {
                 for (const variable of context.getDeclaredVariables(node)) {
-                    if (variable.defs.length > 0 && RESTRICTED.includes(variable.name)) {
+                    if (variable.defs.length > 0 && RESTRICTED.has(variable.name) && !safelyShadowsUndefined(variable)) {
                         context.report({
                             node: variable.defs[0].name,
                             message: "Shadowing of global property '{{idName}}'.",
diff --git a/lib/rules/object-shorthand.js b/lib/rules/object-shorthand.js
index ff6a51a4d..31010f0e7 100644
--- a/lib/rules/object-shorthand.js
+++ b/lib/rules/object-shorthand.js
@@ -255,7 +255,7 @@ module.exports = {
                     keyPrefix + keyText + sourceCode.text.slice(tokenBeforeParams.range[1], node.value.range[1])
                 );
             }
-            const arrowToken = sourceCode.getTokens(node.value).find(token => token.value === "=>");
+            const arrowToken = sourceCode.getTokenBefore(node.value.body, { filter: token => token.value === "=>" });
             const tokenBeforeArrow = sourceCode.getTokenBefore(arrowToken);
             const hasParensAroundParameters = tokenBeforeArrow.type === "Punctuator" && tokenBeforeArrow.value === ")";
             const oldParamText = sourceCode.text.slice(sourceCode.getFirstToken(node.value, node.value.async ? 1 : 0).range[0], tokenBeforeArrow.range[1]);
diff --git a/lib/util/config-comment-parser.js b/lib/util/config-comment-parser.js
index 88504caf1..8ee0230cb 100644
--- a/lib/util/config-comment-parser.js
+++ b/lib/util/config-comment-parser.js
@@ -26,14 +26,14 @@ const debug = require("debug")("eslint:config-comment-parser");
 module.exports = class ConfigCommentParser {
 
     /**
-     * Parses a list of "name:boolean_value" or/and "name" options divided by comma or
+     * Parses a list of "name:string_value" or/and "name" options divided by comma or
      * whitespace. Used for "global" and "exported" comments.
      * @param {string} string The string to parse.
      * @param {Comment} comment The comment node which has the string.
-     * @returns {Object} Result map object of names and boolean values
+     * @returns {Object} Result map object of names and string values, or null values if no value was provided
      */
-    parseBooleanConfig(string, comment) {
-        debug("Parsing Boolean config");
+    parseStringConfig(string, comment) {
+        debug("Parsing String config");
 
         const items = {};
 
@@ -45,13 +45,10 @@ module.exports = class ConfigCommentParser {
                 return;
             }
 
-            // value defaults to "false" (if not provided), e.g: "foo" => ["foo", "false"]
-            const [key, value = "false"] = name.split(":");
+            // value defaults to null (if not provided), e.g: "foo" => ["foo", null]
+            const [key, value = null] = name.split(":");
 
-            items[key] = {
-                value: value === "true",
-                comment
-            };
+            items[key] = { value, comment };
         });
         return items;
     }
diff --git a/package.json b/package.json
index 373c51776..f1776d804 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "eslint",
-  "version": "5.12.1",
+  "version": "5.13.0",
   "author": "Nicholas C. Zakas <nicholas+npm@nczconsulting.com>",
   "description": "An AST-based pattern checker for JavaScript.",
   "bin": {
@@ -47,7 +47,7 @@
     "espree": "^5.0.0",
     "esquery": "^1.0.1",
     "esutils": "^2.0.2",
-    "file-entry-cache": "^2.0.0",
+    "file-entry-cache": "^5.0.1",
     "functional-red-black-tree": "^1.0.1",
     "glob": "^7.1.2",
     "globals": "^11.7.0",
@@ -64,7 +64,6 @@
     "natural-compare": "^1.4.0",
     "optionator": "^0.8.2",
     "path-is-inside": "^1.0.2",
-    "pluralize": "^7.0.0",
     "progress": "^2.0.0",
     "regexpp": "^2.0.1",
     "semver": "^5.5.1",


Test patch:
diff --git a/tests/lib/cli-engine.js b/tests/lib/cli-engine.js
index fd961cb63..f2cfb0318 100644
--- a/tests/lib/cli-engine.js
+++ b/tests/lib/cli-engine.js
@@ -21,6 +21,8 @@ const assert = require("chai").assert,
 
 const proxyquire = require("proxyquire").noCallThru().noPreserveCache();
 
+const fCache = require("file-entry-cache");
+
 //------------------------------------------------------------------------------
 // Tests
 //------------------------------------------------------------------------------
@@ -2375,11 +2377,12 @@ describe("CLIEngine", () => {
 
                 assert.isTrue(shell.test("-f", cacheFile), "the cache for eslint was created");
 
-                const cache = JSON.parse(fs.readFileSync(cacheFile));
+                const fileCache = fCache.createFromFile(cacheFile);
+                const { cache } = fileCache;
 
-                assert.isTrue(typeof cache[goodFile] === "object", "the entry for the good file is in the cache");
+                assert.isTrue(typeof cache.getKey(goodFile) === "object", "the entry for the good file is in the cache");
 
-                assert.isTrue(typeof cache[badFile] === "object", "the entry for the bad file is in the cache");
+                assert.isTrue(typeof cache.getKey(badFile) === "object", "the entry for the bad file is in the cache");
 
                 const cachedResult = engine.executeOnFiles([badFile, goodFile]);
 
@@ -2412,9 +2415,10 @@ describe("CLIEngine", () => {
 
                 engine.executeOnFiles([badFile, goodFile, toBeDeletedFile]);
 
-                let cache = JSON.parse(fs.readFileSync(cacheFile));
+                const fileCache = fCache.createFromFile(cacheFile);
+                let { cache } = fileCache;
 
-                assert.isTrue(typeof cache[toBeDeletedFile] === "object", "the entry for the file to be deleted is in the cache");
+                assert.isTrue(typeof cache.getKey(toBeDeletedFile) === "object", "the entry for the file to be deleted is in the cache");
 
                 // delete the file from the file system
                 fs.unlinkSync(toBeDeletedFile);
@@ -2456,9 +2460,10 @@ describe("CLIEngine", () => {
 
                 engine.executeOnFiles([badFile, goodFile, testFile2]);
 
-                let cache = JSON.parse(fs.readFileSync(cacheFile));
+                let fileCache = fCache.createFromFile(cacheFile);
+                let { cache } = fileCache;
 
-                assert.isTrue(typeof cache[testFile2] === "object", "the entry for the test-file2 is in the cache");
+                assert.isTrue(typeof cache.getKey(testFile2) === "object", "the entry for the test-file2 is in the cache");
 
                 /*
                  * we pass a different set of files minus test-file2
@@ -2467,9 +2472,10 @@ describe("CLIEngine", () => {
                  */
                 engine.executeOnFiles([badFile, goodFile]);
 
-                cache = JSON.parse(fs.readFileSync(cacheFile));
+                fileCache = fCache.createFromFile(cacheFile);
+                cache = fileCache.cache;
 
-                assert.isTrue(typeof cache[testFile2] === "object", "the entry for the test-file2 is in the cache");
+                assert.isTrue(typeof cache.getKey(testFile2) === "object", "the entry for the test-file2 is in the cache");
             });
 
             it("should not delete cache when executing on text", () => {
@@ -2590,11 +2596,12 @@ describe("CLIEngine", () => {
 
                     assert.isTrue(shell.test("-f", customCacheFile), "the cache for eslint was created");
 
-                    const cache = JSON.parse(fs.readFileSync(customCacheFile));
+                    const fileCache = fCache.createFromFile(customCacheFile);
+                    const { cache } = fileCache;
 
-                    assert.isTrue(typeof cache[goodFile] === "object", "the entry for the good file is in the cache");
+                    assert.isTrue(typeof cache.getKey(goodFile) === "object", "the entry for the good file is in the cache");
 
-                    assert.isTrue(typeof cache[badFile] === "object", "the entry for the bad file is in the cache");
+                    assert.isTrue(typeof cache.getKey(badFile) === "object", "the entry for the bad file is in the cache");
 
                     const cachedResult = engine.executeOnFiles([badFile, goodFile]);
 
diff --git a/tests/lib/config/config-file.js b/tests/lib/config/config-file.js
index 944ed8426..c884c7b15 100644
--- a/tests/lib/config/config-file.js
+++ b/tests/lib/config/config-file.js
@@ -20,6 +20,7 @@ const Module = require("module"),
     espree = require("espree"),
     ConfigFile = require("../../../lib/config/config-file"),
     Linter = require("../../../lib/linter"),
+    CLIEngine = require("../../../lib/cli-engine"),
     Config = require("../../../lib/config");
 
 const userHome = os.homedir();
@@ -1262,6 +1263,51 @@ describe("ConfigFile", () => {
 
         });
 
+        it("should make sure js config files match linting rules", () => {
+            const fakeFS = leche.fake(fs);
+
+            const singleQuoteConfig = {
+                rules: {
+                    quotes: [2, "single"]
+                }
+            };
+
+            sandbox.mock(fakeFS).expects("writeFileSync").withExactArgs(
+                "test-config.js",
+                sinon.match(value => !value.includes("\"")),
+                "utf8"
+            );
+
+            const StubbedConfigFile = proxyquire("../../../lib/config/config-file", {
+                fs: fakeFS
+            });
+
+            StubbedConfigFile.write(singleQuoteConfig, "test-config.js");
+        });
+
+        it("should still write a js config file even if linting fails", () => {
+            const fakeFS = leche.fake(fs);
+            const fakeCLIEngine = sandbox.mock().withExactArgs(sinon.match({
+                baseConfig: config,
+                fix: true,
+                useEslintrc: false
+            }));
+
+            fakeCLIEngine.prototype = leche.fake(CLIEngine.prototype);
+            sandbox.stub(fakeCLIEngine.prototype, "executeOnText").throws();
+
+            sandbox.mock(fakeFS).expects("writeFileSync").once();
+
+            const StubbedConfigFile = proxyquire("../../../lib/config/config-file", {
+                fs: fakeFS,
+                "../cli-engine": fakeCLIEngine
+            });
+
+            assert.throws(() => {
+                StubbedConfigFile.write(config, "test-config.js");
+            });
+        });
+
         it("should throw error if file extension is not valid", () => {
             assert.throws(() => {
                 ConfigFile.write({}, getFixturePath("yaml/.eslintrc.class"));
diff --git a/tests/lib/config/config-ops.js b/tests/lib/config/config-ops.js
index f570a1c6f..7cde4ff0f 100644
--- a/tests/lib/config/config-ops.js
+++ b/tests/lib/config/config-ops.js
@@ -898,4 +898,23 @@ describe("ConfigOps", () => {
         error("foo.js", ["/foo.js"], "Invalid override pattern (expected relative path not containing '..'): /foo.js");
         error("foo.js", ["../**"], "Invalid override pattern (expected relative path not containing '..'): ../**");
     });
+
+    describe("normalizeConfigGlobal", () => {
+        [
+            ["off", "off"],
+            [true, "writeable"],
+            ["true", "writeable"],
+            [false, "readable"],
+            ["false", "readable"],
+            [null, "readable"],
+            ["writeable", "writeable"],
+            ["readable", "readable"],
+            ["writable", "writeable"],
+            ["something else", "writeable"]
+        ].forEach(([input, output]) => {
+            it(util.inspect(input), () => {
+                assert.strictEqual(ConfigOps.normalizeConfigGlobal(input), output);
+            });
+        });
+    });
 });
diff --git a/tests/lib/linter.js b/tests/lib/linter.js
index ebe59625b..564bcee6b 100644
--- a/tests/lib/linter.js
+++ b/tests/lib/linter.js
@@ -1124,10 +1124,15 @@ describe("Linter", () => {
     });
 
     describe("when evaluating code containing /*global */ and /*globals */ blocks", () => {
-        const code = "/*global a b:true c:false*/ function foo() {} /*globals d:true*/";
 
         it("variables should be available in global scope", () => {
-            const config = { rules: { checker: "error" } };
+            const config = { rules: { checker: "error" }, globals: { Array: "off", ConfigGlobal: "writeable" } };
+            const code = `
+                /*global a b:true c:false d:readable e:writeable Math:off */
+                function foo() {}
+                /*globals f:true*/
+                /* global ConfigGlobal : readable */
+            `;
             let spy;
 
             linter.defineRule("checker", context => {
@@ -1136,7 +1141,12 @@ describe("Linter", () => {
                     const a = getVariable(scope, "a"),
                         b = getVariable(scope, "b"),
                         c = getVariable(scope, "c"),
-                        d = getVariable(scope, "d");
+                        d = getVariable(scope, "d"),
+                        e = getVariable(scope, "e"),
+                        f = getVariable(scope, "f"),
+                        mathGlobal = getVariable(scope, "Math"),
+                        arrayGlobal = getVariable(scope, "Array"),
+                        configGlobal = getVariable(scope, "ConfigGlobal");
 
                     assert.strictEqual(a.name, "a");
                     assert.strictEqual(a.writeable, false);
@@ -1145,7 +1155,15 @@ describe("Linter", () => {
                     assert.strictEqual(c.name, "c");
                     assert.strictEqual(c.writeable, false);
                     assert.strictEqual(d.name, "d");
-                    assert.strictEqual(d.writeable, true);
+                    assert.strictEqual(d.writeable, false);
+                    assert.strictEqual(e.name, "e");
+                    assert.strictEqual(e.writeable, true);
+                    assert.strictEqual(f.name, "f");
+                    assert.strictEqual(f.writeable, true);
+                    assert.strictEqual(mathGlobal, null);
+                    assert.strictEqual(arrayGlobal, null);
+                    assert.strictEqual(configGlobal.name, "ConfigGlobal");
+                    assert.strictEqual(configGlobal.writeable, false);
                 });
 
                 return { Program: spy };
@@ -1454,6 +1472,26 @@ describe("Linter", () => {
             linter.verify(code, config);
             assert(spy && spy.calledOnce);
         });
+
+        it("ES6 global variables can be disabled when the es6 environment is enabled", () => {
+            const config = { rules: { checker: "error" }, globals: { Promise: "off", Symbol: "off", WeakMap: "off" }, env: { es6: true } };
+            let spy;
+
+            linter.defineRule("checker", context => {
+                spy = sandbox.spy(() => {
+                    const scope = context.getScope();
+
+                    assert.strictEqual(getVariable(scope, "Promise"), null);
+                    assert.strictEqual(getVariable(scope, "Symbol"), null);
+                    assert.strictEqual(getVariable(scope, "WeakMap"), null);
+                });
+
+                return { Program: spy };
+            });
+
+            linter.verify(code, config);
+            assert(spy && spy.calledOnce);
+        });
     });
 
     describe("at any time", () => {
diff --git a/tests/lib/rules/camelcase.js b/tests/lib/rules/camelcase.js
index eb80b4ef4..c8a3914e6 100644
--- a/tests/lib/rules/camelcase.js
+++ b/tests/lib/rules/camelcase.js
@@ -202,6 +202,11 @@ ruleTester.run("camelcase", rule, {
         {
             code: "__option_foo__ = 0;",
             options: [{ allow: ["__option_foo__"] }]
+        },
+        {
+            code: "foo = { [computedBar]: 0 };",
+            options: [{ ignoreDestructuring: true }],
+            parserOptions: { ecmaVersion: 6 }
         }
     ],
     invalid: [
@@ -295,6 +300,17 @@ ruleTester.run("camelcase", rule, {
                 }
             ]
         },
+        {
+            code: "var foo = { bar_baz: boom.bam_pow }",
+            options: [{ ignoreDestructuring: true }],
+            errors: [
+                {
+                    messageId: "notCamelCase",
+                    data: { name: "bar_baz" },
+                    type: "Identifier"
+                }
+            ]
+        },
         {
             code: "foo.qux.boom_pow = { bar: boom.bam_pow }",
             errors: [
@@ -600,6 +616,16 @@ ruleTester.run("camelcase", rule, {
                 }
             ]
         },
+        {
+            code: "const { no_camelcased = foo_bar } = bar;",
+            parserOptions: { ecmaVersion: 6 },
+            errors: [
+                {
+                    message: "Identifier 'no_camelcased' is not in camel case.",
+                    type: "Identifier"
+                }
+            ]
+        },
         {
             code: "not_ignored_foo = 0;",
             options: [{ allow: ["ignored_bar"] }],
@@ -619,6 +645,17 @@ ruleTester.run("camelcase", rule, {
                     type: "Identifier"
                 }
             ]
+        },
+        {
+            code: "foo = { [computed_bar]: 0 };",
+            options: [{ ignoreDestructuring: true }],
+            parserOptions: { ecmaVersion: 6 },
+            errors: [
+                {
+                    message: "Identifier 'computed_bar' is not in camel case.",
+                    type: "Identifier"
+                }
+            ]
         }
     ]
 });
diff --git a/tests/lib/rules/comma-dangle.js b/tests/lib/rules/comma-dangle.js
index 7cd958231..8797dbdcf 100644
--- a/tests/lib/rules/comma-dangle.js
+++ b/tests/lib/rules/comma-dangle.js
@@ -1290,12 +1290,12 @@ ruleTester.run("comma-dangle", rule, {
             code: `let {a,} = {a: 1,};
 let [b,] = [1,];
 import {c,} from "foo";
-export {d,};
+let d = 0;export {d,};
 (function foo(e,) {})(f,);`,
             output: `let {a} = {a: 1};
 let [b,] = [1,];
 import {c,} from "foo";
-export {d,};
+let d = 0;export {d,};
 (function foo(e,) {})(f,);`,
             options: [{
                 objects: "never",
@@ -1314,12 +1314,12 @@ export {d,};
             code: `let {a,} = {a: 1,};
 let [b,] = [1,];
 import {c,} from "foo";
-export {d,};
+let d = 0;export {d,};
 (function foo(e,) {})(f,);`,
             output: `let {a,} = {a: 1,};
 let [b] = [1];
 import {c,} from "foo";
-export {d,};
+let d = 0;export {d,};
 (function foo(e,) {})(f,);`,
             options: [{
                 objects: "ignore",
@@ -1338,12 +1338,12 @@ export {d,};
             code: `let {a,} = {a: 1,};
 let [b,] = [1,];
 import {c,} from "foo";
-export {d,};
+let d = 0;export {d,};
 (function foo(e,) {})(f,);`,
             output: `let {a,} = {a: 1,};
 let [b,] = [1,];
 import {c} from "foo";
-export {d,};
+let d = 0;export {d,};
 (function foo(e,) {})(f,);`,
             options: [{
                 objects: "ignore",
@@ -1361,12 +1361,12 @@ export {d,};
             code: `let {a,} = {a: 1,};
 let [b,] = [1,];
 import {c,} from "foo";
-export {d,};
+let d = 0;export {d,};
 (function foo(e,) {})(f,);`,
             output: `let {a,} = {a: 1,};
 let [b,] = [1,];
 import {c,} from "foo";
-export {d};
+let d = 0;export {d};
 (function foo(e,) {})(f,);`,
             options: [{
                 objects: "ignore",
@@ -1384,12 +1384,12 @@ export {d};
             code: `let {a,} = {a: 1,};
 let [b,] = [1,];
 import {c,} from "foo";
-export {d,};
+let d = 0;export {d,};
 (function foo(e,) {})(f,);`,
             output: `let {a,} = {a: 1,};
 let [b,] = [1,];
 import {c,} from "foo";
-export {d,};
+let d = 0;export {d,};
 (function foo(e) {})(f);`,
             options: [{
                 objects: "ignore",
diff --git a/tests/lib/rules/for-direction.js b/tests/lib/rules/for-direction.js
index e90d3bd52..d42dcc30d 100644
--- a/tests/lib/rules/for-direction.js
+++ b/tests/lib/rules/for-direction.js
@@ -31,10 +31,12 @@ ruleTester.run("for-direction", rule, {
         // test if '+=', '-=',
         "for(var i = 0; i < 10; i+=1){}",
         "for(var i = 0; i <= 10; i+=1){}",
+        "for(var i = 0; i < 10; i-=-1){}",
+        "for(var i = 0; i <= 10; i-=-1){}",
         "for(var i = 10; i > 0; i-=1){}",
         "for(var i = 10; i >= 0; i-=1){}",
-        "for (var i = 0; i < MAX; i += STEP_SIZE);",
-        "for (var i = MAX; i > MIN; i -= STEP_SIZE);",
+        "for(var i = 10; i > 0; i+=-1){}",
+        "for(var i = 10; i >= 0; i+=-1){}",
 
         // test if no update.
         "for(var i = 10; i > 0;){}",
@@ -48,7 +50,10 @@ ruleTester.run("for-direction", rule, {
         "for(var i = 10; i >= 0; j += 2){}",
         "for(var i = 10; i >= 0; j -= 2){}",
         "for(var i = 10; i >= 0; i |= 2){}",
-        "for(var i = 10; i >= 0; i %= 2){}"
+        "for(var i = 10; i >= 0; i %= 2){}",
+        "for(var i = 0; i < MAX; i += STEP_SIZE);",
+        "for(var i = 0; i < MAX; i -= STEP_SIZE);",
+        "for(var i = 10; i > 0; i += STEP_SIZE);"
     ],
     invalid: [
 
@@ -63,7 +68,9 @@ ruleTester.run("for-direction", rule, {
         { code: "for(var i = 0; i <= 10; i-=1){}", errors: [incorrectDirection] },
         { code: "for(var i = 10; i > 10; i+=1){}", errors: [incorrectDirection] },
         { code: "for(var i = 10; i >= 0; i+=1){}", errors: [incorrectDirection] },
-        { code: "for (var i = 0; i < MAX; i -= STEP_SIZE);", errors: [incorrectDirection] },
-        { code: "for (var i = 0; i > MIN; i += STEP_SIZE);", errors: [incorrectDirection] }
+        { code: "for(var i = 0; i < 10; i+=-1){}", errors: [incorrectDirection] },
+        { code: "for(var i = 0; i <= 10; i+=-1){}", errors: [incorrectDirection] },
+        { code: "for(var i = 10; i > 10; i-=-1){}", errors: [incorrectDirection] },
+        { code: "for(var i = 10; i >= 0; i-=-1){}", errors: [incorrectDirection] }
     ]
 });
diff --git a/tests/lib/rules/indent.js b/tests/lib/rules/indent.js
index 7571d3aaf..06dd77d38 100644
--- a/tests/lib/rules/indent.js
+++ b/tests/lib/rules/indent.js
@@ -1109,6 +1109,7 @@ ruleTester.run("indent", rule, {
         },
         {
             code: unIndent`
+                var foo = 0, bar = 0; baz = 0;
                 export {
                     foo,
                     bar,
@@ -3100,6 +3101,7 @@ ruleTester.run("indent", rule, {
         `,
         {
             code: unIndent`
+                var foo = 0, bar = 0, baz = 0;
                 export {
                     foo,
                     bar,
@@ -4813,6 +4815,7 @@ ruleTester.run("indent", rule, {
         },
         {
             code: unIndent`
+                var a = 0, b = 0, c = 0;
                 export default foo(
                     a,
                     b, {
@@ -7620,6 +7623,7 @@ ruleTester.run("indent", rule, {
         },
         {
             code: unIndent`
+                var foo = 0, bar = 0, baz = 0;
                 export {
                 foo,
                   bar,
@@ -7627,6 +7631,7 @@ ruleTester.run("indent", rule, {
                 };
             `,
             output: unIndent`
+                var foo = 0, bar = 0, baz = 0;
                 export {
                     foo,
                     bar,
@@ -7634,10 +7639,11 @@ ruleTester.run("indent", rule, {
                 };
             `,
             parserOptions: { sourceType: "module" },
-            errors: expectedErrors([[2, 4, 0, "Identifier"], [3, 4, 2, "Identifier"]])
+            errors: expectedErrors([[3, 4, 0, "Identifier"], [4, 4, 2, "Identifier"]])
         },
         {
             code: unIndent`
+                var foo = 0, bar = 0, baz = 0;
                 export {
                 foo,
                   bar,
@@ -7645,6 +7651,7 @@ ruleTester.run("indent", rule, {
                 } from 'qux';
             `,
             output: unIndent`
+                var foo = 0, bar = 0, baz = 0;
                 export {
                     foo,
                     bar,
@@ -7652,7 +7659,7 @@ ruleTester.run("indent", rule, {
                 } from 'qux';
             `,
             parserOptions: { sourceType: "module" },
-            errors: expectedErrors([[2, 4, 0, "Identifier"], [3, 4, 2, "Identifier"]])
+            errors: expectedErrors([[3, 4, 0, "Identifier"], [4, 4, 2, "Identifier"]])
         },
         {
 
@@ -8074,6 +8081,7 @@ ruleTester.run("indent", rule, {
         },
         {
             code: unIndent`
+                var foo = 0, bar = 0, baz = 0;
                 export {
                 foo,
                         bar,
@@ -8081,6 +8089,7 @@ ruleTester.run("indent", rule, {
                 }
             `,
             output: unIndent`
+                var foo = 0, bar = 0, baz = 0;
                 export {
                     foo,
                     bar,
@@ -8088,7 +8097,7 @@ ruleTester.run("indent", rule, {
                 }
             `,
             parserOptions: { sourceType: "module" },
-            errors: expectedErrors([[2, 4, 0, "Identifier"], [3, 4, 8, "Identifier"], [4, 4, 2, "Identifier"]])
+            errors: expectedErrors([[3, 4, 0, "Identifier"], [4, 4, 8, "Identifier"], [5, 4, 2, "Identifier"]])
         },
         {
             code: unIndent`
diff --git a/tests/lib/rules/keyword-spacing.js b/tests/lib/rules/keyword-spacing.js
index 84c5d74a6..5e6a0d837 100644
--- a/tests/lib/rules/keyword-spacing.js
+++ b/tests/lib/rules/keyword-spacing.js
@@ -561,16 +561,16 @@ ruleTester.run("keyword-spacing", rule, {
         // export
         //----------------------------------------------------------------------
 
-        { code: "{} export {a}", parserOptions: { sourceType: "module" } },
+        { code: "var a = 0; {} export {a}", parserOptions: { sourceType: "module" } },
         { code: "{} export default a", parserOptions: { sourceType: "module" } },
         { code: "{} export * from \"a\"", parserOptions: { sourceType: "module" } },
-        { code: "{}export{a}", options: [NEITHER], parserOptions: { sourceType: "module" } },
-        { code: "{} export {a}", options: [override("export", BOTH)], parserOptions: { sourceType: "module" } },
-        { code: "{}export{a}", options: [override("export", NEITHER)], parserOptions: { sourceType: "module" } },
+        { code: "var a = 0; {}export{a}", options: [NEITHER], parserOptions: { sourceType: "module" } },
+        { code: "var a = 0; {} export {a}", options: [override("export", BOTH)], parserOptions: { sourceType: "module" } },
+        { code: "var a = 0; {}export{a}", options: [override("export", NEITHER)], parserOptions: { sourceType: "module" } },
 
         // not conflict with `semi-spacing`
-        { code: ";export {a}", parserOptions: { sourceType: "module" } },
-        { code: "; export{a}", options: [NEITHER], parserOptions: { sourceType: "module" } },
+        { code: "var a = 0;\n;export {a}", parserOptions: { sourceType: "module" } },
+        { code: "var a = 0;\n; export{a}", options: [NEITHER], parserOptions: { sourceType: "module" } },
 
         //----------------------------------------------------------------------
         // extends
@@ -2012,20 +2012,20 @@ ruleTester.run("keyword-spacing", rule, {
         //----------------------------------------------------------------------
 
         {
-            code: "{}export{a}",
-            output: "{} export {a}",
+            code: "var a = 0; {}export{a}",
+            output: "var a = 0; {} export {a}",
             parserOptions: { sourceType: "module" },
             errors: expectedBeforeAndAfter("export")
         },
         {
-            code: "{}export default a",
-            output: "{} export default a",
+            code: "var a = 0; {}export default a",
+            output: "var a = 0; {} export default a",
             parserOptions: { sourceType: "module" },
             errors: expectedBefore("export")
         },
         {
-            code: "export default{a}",
-            output: "export default {a}",
+            code: "var a = 0; export default{a}",
+            output: "var a = 0; export default {a}",
             parserOptions: { sourceType: "module" },
             errors: expectedAfter("default")
         },
@@ -2036,22 +2036,22 @@ ruleTester.run("keyword-spacing", rule, {
             errors: expectedBeforeAndAfter("export")
         },
         {
-            code: "{} export {a}",
-            output: "{}export{a}",
+            code: "var a = 0; {} export {a}",
+            output: "var a = 0; {}export{a}",
             options: [NEITHER],
             parserOptions: { sourceType: "module" },
             errors: unexpectedBeforeAndAfter("export")
         },
         {
-            code: "{}export{a}",
-            output: "{} export {a}",
+            code: "var a = 0; {}export{a}",
+            output: "var a = 0; {} export {a}",
             options: [override("export", BOTH)],
             parserOptions: { sourceType: "module" },
             errors: expectedBeforeAndAfter("export")
         },
         {
-            code: "{} export {a}",
-            output: "{}export{a}",
+            code: "var a = 0; {} export {a}",
+            output: "var a = 0; {}export{a}",
             options: [override("export", NEITHER)],
             parserOptions: { sourceType: "module" },
             errors: unexpectedBeforeAndAfter("export")
diff --git a/tests/lib/rules/no-constant-condition.js b/tests/lib/rules/no-constant-condition.js
index c89f9080d..e27e3b390 100644
--- a/tests/lib/rules/no-constant-condition.js
+++ b/tests/lib/rules/no-constant-condition.js
@@ -61,6 +61,18 @@ ruleTester.run("no-constant-condition", rule, {
         "if(a && 'str'){}",
         "if('str' || abc==='str'){}",
 
+        // #11306
+        "if ((foo || 'bar') === 'baz') {}",
+        "if ((foo || 'bar') !== 'baz') {}",
+        "if ((foo || 'bar') == 'baz') {}",
+        "if ((foo || 'bar') != 'baz') {}",
+        "if ((foo || 233) > 666) {}",
+        "if ((foo || 233) < 666) {}",
+        "if ((foo || 233) >= 666) {}",
+        "if ((foo || 233) <= 666) {}",
+        "if ((key || 'k') in obj) {}",
+        "if ((foo || {}) instanceof obj) {}",
+
         // { checkLoops: false }
         { code: "while(true);", options: [{ checkLoops: false }] },
         { code: "for(;true;);", options: [{ checkLoops: false }] },
diff --git a/tests/lib/rules/no-irregular-whitespace.js b/tests/lib/rules/no-irregular-whitespace.js
index 492b2e993..bf5dcb455 100644
--- a/tests/lib/rules/no-irregular-whitespace.js
+++ b/tests/lib/rules/no-irregular-whitespace.js
@@ -181,10 +181,15 @@ ruleTester.run("no-irregular-whitespace", rule, {
             code: "var any \u00A0 = 'thing';",
             errors: expectedErrors
         },
-        {
-            code: "var any \u180E = 'thing';",
-            errors: expectedErrors
-        },
+
+        /*
+         * it was moved out of General_Category=Zs (separator, space) in Unicode 6.3.0, so should not be considered a whitespace character.
+         * https://codeblog.jonskeet.uk/2014/12/01/when-is-an-identifier-not-an-identifier-attack-of-the-mongolian-vowel-separator/
+         * {
+         *     code: "var any \u180E = 'thing';",
+         *     errors: expectedErrors
+         * },
+         */
         {
             code: "var any \ufeff = 'thing';",
             errors: expectedErrors
diff --git a/tests/lib/rules/no-shadow-restricted-names.js b/tests/lib/rules/no-shadow-restricted-names.js
index 3c014a70f..cfc40a82c 100644
--- a/tests/lib/rules/no-shadow-restricted-names.js
+++ b/tests/lib/rules/no-shadow-restricted-names.js
@@ -24,6 +24,13 @@ ruleTester.run("no-shadow-restricted-names", rule, {
         {
             code: "try {} catch {}",
             parserOptions: { ecmaVersion: 2019 }
+        },
+        "var undefined;",
+        "var undefined; doSomething(undefined);",
+        "var undefined; var undefined;",
+        {
+            code: "let undefined",
+            parserOptions: { ecmaVersion: 2015 }
         }
     ],
     invalid: [
@@ -39,13 +46,12 @@ ruleTester.run("no-shadow-restricted-names", rule, {
             ]
         },
         {
-            code: "function undefined(undefined) { var undefined; !function undefined(undefined) { try {} catch(undefined) {} }; }",
+            code: "function undefined(undefined) { !function undefined(undefined) { try {} catch(undefined) {} }; }",
             errors: [
                 { message: "Shadowing of global property 'undefined'.", type: "Identifier" },
                 { message: "Shadowing of global property 'undefined'.", type: "Identifier" },
                 { message: "Shadowing of global property 'undefined'.", type: "Identifier" },
                 { message: "Shadowing of global property 'undefined'.", type: "Identifier" },
-                { message: "Shadowing of global property 'undefined'.", type: "Identifier" },
                 { message: "Shadowing of global property 'undefined'.", type: "Identifier" }
             ]
         },
@@ -110,6 +116,12 @@ ruleTester.run("no-shadow-restricted-names", rule, {
                 { message: "Shadowing of global property 'undefined'.", type: "Identifier" },
                 { message: "Shadowing of global property 'undefined'.", type: "Identifier" }
             ]
+        },
+        {
+            code: "var undefined; undefined = 5;",
+            errors: [
+                { message: "Shadowing of global property 'undefined'.", type: "Identifier" }
+            ]
         }
     ]
 });
diff --git a/tests/lib/rules/no-undefined.js b/tests/lib/rules/no-undefined.js
index bc5706854..bcc18b242 100644
--- a/tests/lib/rules/no-undefined.js
+++ b/tests/lib/rules/no-undefined.js
@@ -111,11 +111,15 @@ ruleTester.run("no-undefined", rule, {
             parserOptions: ES6_MODULE,
             errors
         },
-        {
-            code: "export { undefined }",
-            parserOptions: ES6_MODULE,
-            errors
-        },
+
+        /*
+         * it will be warned "Parsing error: Export 'undefined' is not defined" (acorn@>=6.0.7)
+         * {
+         *     code: "export { undefined }",
+         *     parserOptions: ES6_MODULE,
+         *     errors
+         * },
+         */
         { code: "let a = [b, ...undefined]", errors },
         { code: "[a, ...undefined] = b", errors },
         { code: "[a = undefined] = b", errors }
diff --git a/tests/lib/rules/no-useless-rename.js b/tests/lib/rules/no-useless-rename.js
index 2a864c06b..9f7e0777a 100644
--- a/tests/lib/rules/no-useless-rename.js
+++ b/tests/lib/rules/no-useless-rename.js
@@ -44,8 +44,8 @@ ruleTester.run("no-useless-rename", rule, {
         "import {foo as bar} from 'foo';",
         "import {foo as bar, baz as qux} from 'foo';",
         "export {foo} from 'foo';",
-        "export {foo as bar};",
-        "export {foo as bar, baz as qux};",
+        "var foo = 0;export {foo as bar};",
+        "var foo = 0; var baz = 0; export {foo as bar, baz as qux};",
         "export {foo as bar} from 'foo';",
         "export {foo as bar, baz as qux} from 'foo';",
         {
@@ -91,15 +91,15 @@ ruleTester.run("no-useless-rename", rule, {
 
         // { ignoreExport: true }
         {
-            code: "export {foo as foo};",
+            code: "var foo = 0;export {foo as foo};",
             options: [{ ignoreExport: true }]
         },
         {
-            code: "export {foo as foo, bar as baz};",
+            code: "var foo = 0;var bar = 0;export {foo as foo, bar as baz};",
             options: [{ ignoreExport: true }]
         },
         {
-            code: "export {foo as foo, bar as bar};",
+            code: "var foo = 0;var bar = 0;export {foo as foo, bar as bar};",
             options: [{ ignoreExport: true }]
         },
         {
@@ -261,23 +261,23 @@ ruleTester.run("no-useless-rename", rule, {
             errors: ["Import foo unnecessarily renamed.", "Import bar unnecessarily renamed."]
         },
         {
-            code: "export {foo as foo};",
-            output: "export {foo};",
+            code: "var foo = 0; export {foo as foo};",
+            output: "var foo = 0; export {foo};",
             errors: ["Export foo unnecessarily renamed."]
         },
         {
-            code: "export {foo as foo, bar as baz};",
-            output: "export {foo, bar as baz};",
+            code: "var foo = 0; var bar = 0; export {foo as foo, bar as baz};",
+            output: "var foo = 0; var bar = 0; export {foo, bar as baz};",
             errors: ["Export foo unnecessarily renamed."]
         },
         {
-            code: "export {foo as bar, baz as baz};",
-            output: "export {foo as bar, baz};",
+            code: "var foo = 0; var baz = 0; export {foo as bar, baz as baz};",
+            output: "var foo = 0; var baz = 0; export {foo as bar, baz};",
             errors: ["Export baz unnecessarily renamed."]
         },
         {
-            code: "export {foo as foo, bar as bar};",
-            output: "export {foo, bar};",
+            code: "var foo = 0; var bar = 0;export {foo as foo, bar as bar};",
+            output: "var foo = 0; var bar = 0;export {foo, bar};",
             errors: ["Export foo unnecessarily renamed.", "Export bar unnecessarily renamed."]
         },
         {
@@ -291,8 +291,8 @@ ruleTester.run("no-useless-rename", rule, {
             errors: ["Export foo unnecessarily renamed."]
         },
         {
-            code: "export {foo as bar, baz as baz} from 'foo';",
-            output: "export {foo as bar, baz} from 'foo';",
+            code: "var foo = 0; var bar = 0; export {foo as bar, baz as baz} from 'foo';",
+            output: "var foo = 0; var bar = 0; export {foo as bar, baz} from 'foo';",
             errors: ["Export baz unnecessarily renamed."]
         },
         {
diff --git a/tests/lib/rules/object-curly-newline.js b/tests/lib/rules/object-curly-newline.js
index ac74c7a5e..072ca1611 100644
--- a/tests/lib/rules/object-curly-newline.js
+++ b/tests/lib/rules/object-curly-newline.js
@@ -515,6 +515,7 @@ ruleTester.run("object-curly-newline", rule, {
         // "ExportDeclaration" ---------------------------------------------
         {
             code: [
+                "var a = 0, b = 0;",
                 "export {a,",
                 "b};"
             ].join("\n"),
@@ -522,6 +523,7 @@ ruleTester.run("object-curly-newline", rule, {
         },
         {
             code: [
+                "var a = 0, b = 0;",
                 "export {",
                 "a as a, b",
                 "} from 'module';"
@@ -1637,19 +1639,21 @@ ruleTester.run("object-curly-newline", rule, {
         // "ExportDeclaration" ---------------------------------------------
         {
             code: [
+                "var a = 0; var b = 0;",
                 "export {",
                 "    a,",
                 "    b",
                 "};"
             ].join("\n"),
             output: [
+                "var a = 0; var b = 0;",
                 "export {a,",
                 "    b};"
             ].join("\n"),
             options: [{ ExportDeclaration: "never" }],
             errors: [
-                { line: 1, column: 8, message: "Unexpected line break after this opening brace." },
-                { line: 4, column: 1, message: "Unexpected line break before this closing brace." }
+                { line: 2, column: 8, message: "Unexpected line break after this opening brace." },
+                { line: 5, column: 1, message: "Unexpected line break before this closing brace." }
             ]
         },
         {
diff --git a/tests/lib/rules/object-curly-spacing.js b/tests/lib/rules/object-curly-spacing.js
index dc2a26180..c016b731b 100644
--- a/tests/lib/rules/object-curly-spacing.js
+++ b/tests/lib/rules/object-curly-spacing.js
@@ -48,7 +48,7 @@ ruleTester.run("object-curly-spacing", rule, {
         { code: "import { house, mouse } from 'caravan'", options: ["always"], parserOptions: { sourceType: "module" } },
         { code: "import house, { mouse } from 'caravan'", options: ["always"], parserOptions: { sourceType: "module" } },
         { code: "import door, { house, mouse } from 'caravan'", options: ["always"], parserOptions: { sourceType: "module" } },
-        { code: "export { door }", options: ["always"], parserOptions: { sourceType: "module" } },
+        { code: "var door = 0;export { door }", options: ["always"], parserOptions: { sourceType: "module" } },
         { code: "import 'room'", options: ["always"], parserOptions: { sourceType: "module" } },
         { code: "import { bar as x } from 'foo';", options: ["always"], parserOptions: { sourceType: "module" } },
         { code: "import { x, } from 'foo';", options: ["always"], parserOptions: { sourceType: "module" } },
@@ -107,7 +107,7 @@ ruleTester.run("object-curly-spacing", rule, {
         { code: "export {\ndoor\n} from 'room'", options: ["never"], parserOptions: { sourceType: "module" } },
         { code: "import {house,mouse} from 'caravan'", options: ["never"], parserOptions: { sourceType: "module" } },
         { code: "import {house, mouse} from 'caravan'", options: ["never"], parserOptions: { sourceType: "module" } },
-        { code: "export {door}", options: ["never"], parserOptions: { sourceType: "module" } },
+        { code: "var door = 0;export {door}", options: ["never"], parserOptions: { sourceType: "module" } },
         { code: "import 'room'", options: ["never"], parserOptions: { sourceType: "module" } },
         { code: "import x, {bar} from 'foo';", options: ["never"], parserOptions: { sourceType: "module" } },
         { code: "import x, {bar, baz} from 'foo';", options: ["never"], parserOptions: { sourceType: "module" } },
@@ -333,21 +333,21 @@ ruleTester.run("object-curly-spacing", rule, {
             ]
         },
         {
-            code: "export {bar};",
-            output: "export { bar };",
+            code: "var bar = 0;\nexport {bar};",
+            output: "var bar = 0;\nexport { bar };",
             options: ["always"],
             parserOptions: { sourceType: "module" },
             errors: [
                 {
                     message: "A space is required after '{'.",
                     type: "ExportNamedDeclaration",
-                    line: 1,
+                    line: 2,
                     column: 8
                 },
                 {
                     message: "A space is required before '}'.",
                     type: "ExportNamedDeclaration",
-                    line: 1,
+                    line: 2,
                     column: 12
                 }
             ]
diff --git a/tests/lib/rules/object-shorthand.js b/tests/lib/rules/object-shorthand.js
index c52f43af0..19d235290 100644
--- a/tests/lib/rules/object-shorthand.js
+++ b/tests/lib/rules/object-shorthand.js
@@ -931,6 +931,14 @@ ruleTester.run("object-shorthand", rule, {
             parserOptions: { ecmaVersion: 8 },
             errors: [METHOD_ERROR]
         },
+        {
+
+            // https://github.com/eslint/eslint/issues/11305
+            code: "({ key: (arg = () => {}) => {} })",
+            output: "({ key(arg = () => {}) {} })",
+            options: ["always", { avoidExplicitReturnArrows: true }],
+            errors: [METHOD_ERROR]
+        },
         {
             code: `
                 function foo() {
diff --git a/tests/lib/rules/padding-line-between-statements.js b/tests/lib/rules/padding-line-between-statements.js
index dc5d81c42..c9d703528 100644
--- a/tests/lib/rules/padding-line-between-statements.js
+++ b/tests/lib/rules/padding-line-between-statements.js
@@ -736,7 +736,7 @@ ruleTester.run("padding-line-between-statements", rule, {
             parserOptions: { sourceType: "module" }
         },
         {
-            code: "export {a}\n\nfoo()",
+            code: "var a = 0; export {a}\n\nfoo()",
             options: [
                 { blankLine: "never", prev: "*", next: "*" },
                 { blankLine: "always", prev: "export", next: "*" }
@@ -3442,8 +3442,8 @@ ruleTester.run("padding-line-between-statements", rule, {
             errors: [MESSAGE_NEVER]
         },
         {
-            code: "export {a}\n\nfoo()",
-            output: "export {a}\nfoo()",
+            code: "var a = 0;export {a}\n\nfoo()",
+            output: "var a = 0;export {a}\nfoo()",
             options: [
                 { blankLine: "never", prev: "export", next: "*" }
             ],
@@ -3469,8 +3469,8 @@ ruleTester.run("padding-line-between-statements", rule, {
             errors: [MESSAGE_ALWAYS]
         },
         {
-            code: "export {a}\nfoo()",
-            output: "export {a}\n\nfoo()",
+            code: "var a = 0;export {a}\nfoo()",
+            output: "var a = 0;export {a}\n\nfoo()",
             options: [
                 { blankLine: "always", prev: "export", next: "*" }
             ],
diff --git a/tests/lib/rules/semi-spacing.js b/tests/lib/rules/semi-spacing.js
index 2fde1d11a..27aefa05a 100644
--- a/tests/lib/rules/semi-spacing.js
+++ b/tests/lib/rules/semi-spacing.js
@@ -183,12 +183,12 @@ ruleTester.run("semi-spacing", rule, {
             ]
         },
         {
-            code: "export {foo} ;",
-            output: "export {foo};",
+            code: "var foo = 0; export {foo} ;",
+            output: "var foo = 0; export {foo};",
             options: [{ before: false, after: true }],
             parserOptions: { sourceType: "module" },
             errors: [
-                { message: "Unexpected whitespace before semicolon.", type: "ExportNamedDeclaration", line: 1, column: 14 }
+                { message: "Unexpected whitespace before semicolon.", type: "ExportNamedDeclaration", line: 1, column: 27 }
             ]
         },
         {
diff --git a/tests/lib/rules/semi.js b/tests/lib/rules/semi.js
index a8bb03424..13b13f20e 100644
--- a/tests/lib/rules/semi.js
+++ b/tests/lib/rules/semi.js
@@ -59,7 +59,7 @@ ruleTester.run("semi", rule, {
         // exports, "always"
         { code: "export * from 'foo';", parserOptions: { sourceType: "module" } },
         { code: "export { foo } from 'foo';", parserOptions: { sourceType: "module" } },
-        { code: "export { foo };", parserOptions: { sourceType: "module" } },
+        { code: "var foo = 0;export { foo };", parserOptions: { sourceType: "module" } },
         { code: "export var foo;", parserOptions: { sourceType: "module" } },
         { code: "export function foo () { }", parserOptions: { sourceType: "module" } },
         { code: "export function* foo () { }", parserOptions: { sourceType: "module" } },
@@ -77,7 +77,7 @@ ruleTester.run("semi", rule, {
         // exports, "never"
         { code: "export * from 'foo'", options: ["never"], parserOptions: { sourceType: "module" } },
         { code: "export { foo } from 'foo'", options: ["never"], parserOptions: { sourceType: "module" } },
-        { code: "export { foo }", options: ["never"], parserOptions: { sourceType: "module" } },
+        { code: "var foo = 0; export { foo }", options: ["never"], parserOptions: { sourceType: "module" } },
         { code: "export var foo", options: ["never"], parserOptions: { sourceType: "module" } },
         { code: "export function foo () { }", options: ["never"], parserOptions: { sourceType: "module" } },
         { code: "export function* foo () { }", options: ["never"], parserOptions: { sourceType: "module" } },
@@ -123,7 +123,7 @@ ruleTester.run("semi", rule, {
         },
         {
             code: `
-                export {a};
+                var a = 0; export {a};
                 [a] = b
             `,
             options: ["never", { beforeStatementContinuationChars: "always" }],
@@ -182,7 +182,7 @@ ruleTester.run("semi", rule, {
         },
         {
             code: `
-                export {a}
+                var a = 0; export {a}
                 [a] = b
             `,
             options: ["never", { beforeStatementContinuationChars: "never" }],
@@ -281,7 +281,7 @@ ruleTester.run("semi", rule, {
         // exports, "always"
         { code: "export * from 'foo'", output: "export * from 'foo';", parserOptions: { sourceType: "module" }, errors: [{ message: "Missing semicolon.", type: "ExportAllDeclaration" }] },
         { code: "export { foo } from 'foo'", output: "export { foo } from 'foo';", parserOptions: { sourceType: "module" }, errors: [{ message: "Missing semicolon.", type: "ExportNamedDeclaration" }] },
-        { code: "export { foo }", output: "export { foo };", parserOptions: { sourceType: "module" }, errors: [{ message: "Missing semicolon.", type: "ExportNamedDeclaration" }] },
+        { code: "var foo = 0;export { foo }", output: "var foo = 0;export { foo };", parserOptions: { sourceType: "module" }, errors: [{ message: "Missing semicolon.", type: "ExportNamedDeclaration" }] },
         { code: "export var foo", output: "export var foo;", parserOptions: { sourceType: "module" }, errors: [{ message: "Missing semicolon.", type: "VariableDeclaration" }] },
         { code: "export let foo", output: "export let foo;", parserOptions: { sourceType: "module" }, errors: [{ message: "Missing semicolon.", type: "VariableDeclaration" }] },
         { code: "export const FOO = 42", output: "export const FOO = 42;", parserOptions: { sourceType: "module" }, errors: [{ message: "Missing semicolon.", type: "VariableDeclaration" }] },
@@ -293,7 +293,7 @@ ruleTester.run("semi", rule, {
         // exports, "never"
         { code: "export * from 'foo';", output: "export * from 'foo'", options: ["never"], parserOptions: { sourceType: "module" }, errors: [{ message: "Extra semicolon.", type: "ExportAllDeclaration" }] },
         { code: "export { foo } from 'foo';", output: "export { foo } from 'foo'", options: ["never"], parserOptions: { sourceType: "module" }, errors: [{ message: "Extra semicolon.", type: "ExportNamedDeclaration" }] },
-        { code: "export { foo };", output: "export { foo }", options: ["never"], parserOptions: { sourceType: "module" }, errors: [{ message: "Extra semicolon.", type: "ExportNamedDeclaration" }] },
+        { code: "var foo = 0;export { foo };", output: "var foo = 0;export { foo }", options: ["never"], parserOptions: { sourceType: "module" }, errors: [{ message: "Extra semicolon.", type: "ExportNamedDeclaration" }] },
         { code: "export var foo;", output: "export var foo", options: ["never"], parserOptions: { sourceType: "module" }, errors: [{ message: "Extra semicolon.", type: "VariableDeclaration" }] },
         { code: "export let foo;", output: "export let foo", options: ["never"], parserOptions: { sourceType: "module" }, errors: [{ message: "Extra semicolon.", type: "VariableDeclaration" }] },
         { code: "export const FOO = 42;", output: "export const FOO = 42", options: ["never"], parserOptions: { sourceType: "module" }, errors: [{ message: "Extra semicolon.", type: "VariableDeclaration" }] },
@@ -338,11 +338,11 @@ ruleTester.run("semi", rule, {
         },
         {
             code: `
-                export {a}
+                var a = 0; export {a}
                 [a] = b
             `,
             output: `
-                export {a};
+                var a = 0; export {a};
                 [a] = b
             `,
             options: ["never", { beforeStatementContinuationChars: "always" }],
@@ -438,11 +438,11 @@ ruleTester.run("semi", rule, {
         },
         {
             code: `
-                export {a};
+                var a = 0; export {a};
                 [a] = b
             `,
             output: `
-                export {a}
+                var a = 0; export {a}
                 [a] = b
             `,
             options: ["never", { beforeStatementContinuationChars: "never" }],
@@ -538,11 +538,11 @@ ruleTester.run("semi", rule, {
         },
         {
             code: `
-                export {a}
+                var a = 0; export {a}
                 ;[1,2,3].forEach(doSomething)
             `,
             output: `
-                export {a}
+                var a = 0; export {a}
                 [1,2,3].forEach(doSomething)
             `,
             options: ["never", { beforeStatementContinuationChars: "never" }],
diff --git a/tests/lib/util/config-comment-parser.js b/tests/lib/util/config-comment-parser.js
index 6dbe9381a..41583d65c 100644
--- a/tests/lib/util/config-comment-parser.js
+++ b/tests/lib/util/config-comment-parser.js
@@ -117,77 +117,77 @@ describe("ConfigCommentParser", () => {
 
     });
 
-    describe("parseBooleanConfig", () => {
+    describe("parseStringConfig", () => {
 
         const comment = {};
 
-        it("should parse Boolean config with one item", () => {
+        it("should parse String config with one item", () => {
             const code = "a: true";
-            const result = commentParser.parseBooleanConfig(code, comment);
+            const result = commentParser.parseStringConfig(code, comment);
 
             assert.deepStrictEqual(result, {
                 a: {
-                    value: true,
+                    value: "true",
                     comment
                 }
             });
         });
 
-        it("should parse Boolean config with one item and no value", () => {
+        it("should parse String config with one item and no value", () => {
             const code = "a";
-            const result = commentParser.parseBooleanConfig(code, comment);
+            const result = commentParser.parseStringConfig(code, comment);
 
             assert.deepStrictEqual(result, {
                 a: {
-                    value: false,
+                    value: null,
                     comment
                 }
             });
         });
 
-        it("should parse Boolean config with two items", () => {
-            const code = "a: true b:false";
-            const result = commentParser.parseBooleanConfig(code, comment);
+        it("should parse String config with two items", () => {
+            const code = "a: five b:three";
+            const result = commentParser.parseStringConfig(code, comment);
 
             assert.deepStrictEqual(result, {
                 a: {
-                    value: true,
+                    value: "five",
                     comment
                 },
                 b: {
-                    value: false,
+                    value: "three",
                     comment
                 }
             });
         });
 
-        it("should parse Boolean config with two comma-separated items", () => {
-            const code = "a: true, b:false";
-            const result = commentParser.parseBooleanConfig(code, comment);
+        it("should parse String config with two comma-separated items", () => {
+            const code = "a: seventy, b:ELEVENTEEN";
+            const result = commentParser.parseStringConfig(code, comment);
 
             assert.deepStrictEqual(result, {
                 a: {
-                    value: true,
+                    value: "seventy",
                     comment
                 },
                 b: {
-                    value: false,
+                    value: "ELEVENTEEN",
                     comment
                 }
             });
         });
 
-        it("should parse Boolean config with two comma-separated items and no values", () => {
+        it("should parse String config with two comma-separated items and no values", () => {
             const code = "a , b";
-            const result = commentParser.parseBooleanConfig(code, comment);
+            const result = commentParser.parseStringConfig(code, comment);
 
             assert.deepStrictEqual(result, {
                 a: {
-                    value: false,
+                    value: null,
                     comment
                 },
                 b: {
-                    value: false,
+                    value: null,
                     comment
                 }
             });