Repository: eslint/eslint (JavaScript)

Issue:
keyword-spacing else ghost default
<!--
    ESLint adheres to the [JS Foundation Code of Conduct](https://js.foundation/community/code-of-conduct).

    This template is for bug reports. If you are here for another reason, please see below:

    1. To propose a new rule: https://eslint.org/docs/developer-guide/contributing/new-rules
    2. To request a rule change: https://eslint.org/docs/developer-guide/contributing/rule-changes
    3. To request a change that is not a bug fix, rule change, or new rule: https://eslint.org/docs/developer-guide/contributing/changes
    4. If you have any questions, please stop by our chatroom: https://gitter.im/eslint/eslint

    Note that leaving sections blank will make it difficult for us to troubleshoot and we may have to close the issue.
-->

**Tell us about your environment**

<!--
    If you are using ESLint v6.5.0 or later, you can run ESLint with the `--env-info` flag and paste the output here.
-->

* **ESLint Version:** 6.5.1
* **Node Version:** 10.16.3
* **npm Version:** 6.9.0

**What parser (default, Babel-ESLint, etc.) are you using?**
default
**Please show your full configuration:**

<details>
<summary>Configuration</summary>

<!-- Paste your configuration below: -->
```yml
rules: {
  keyword-spacing: ["error", {
    before: false,
    after: true,
    overrides: {
      else: {after: false},
      if: {after: false}
    }
  }],
}
```

</details>

**What did you do? Please include the actual source code causing the issue, as well as the command that you used to run ESLint.**

<!-- Paste the source code below: -->
```js
if(false) {
  console.info("will not log");
}else{
  console.info("will log");
}
```

<!-- Paste the command you used to run ESLint: -->
```bash
eslint index.js
```

**What did you expect to happen?**
`before: false` should set it so every keyword requires no spacing before it, as no overrides set it to `true`.

**What actually happened? Please include the actual, raw output from ESLint.**
```bash
/path/to/my/file/index.js
  3:2  error  Expected space(s) before "else"  keyword-spacing
```
Although the `before` property appears to work on every other keyword added to the overrides I've tried (`if`, for example, works fine using the above config), `else` for some reason sets it to true. Explicitly setting `before: false` in the `else` override appears to be a temporary solution to this bug.

**Are you willing to submit a pull request to fix this bug?**
I am unsure of how it would be fixed, but I would be willing to submit a PR if I did.


Discussion:
Thanks for this issue.

It seems that you've set `after: false` in your configuration, while you're reporting about the `before` option.
I set `before: false` in the configuration as well, yet it's being treated as `before: true` for the `else` keyword, while working as intended for all other keywords I've tried.
I can reproduce ([demo][1]).

If I had to guess, it seems that we might be checking overrides and falling back to defaults incorrectly. The expected behavior would be: Check overrides for the given keyword and location; if not present, check the specified config option for the location; if that's not specified, fall back to the default option for the location. Instead, it looks like we're letting the override object completely replace the location-only config option and then falling back to the rule's default.

[1]: https://eslint.org/demo#eyJ0ZXh0IjoiLyogZXNsaW50IGtleXdvcmQtc3BhY2luZzogW1wiZXJyb3JcIiwge1xuICAgIGJlZm9yZTogZmFsc2UsXG4gICAgYWZ0ZXI6IHRydWUsXG4gICAgb3ZlcnJpZGVzOiB7XG4gICAgICBlbHNlOiB7YWZ0ZXI6IGZhbHNlfSxcbiAgICAgIGlmOiB7YWZ0ZXI6IGZhbHNlfVxuICAgIH1cbiAgfV0gKi9cblxuaWYoZmFsc2UpIHtcbiAgY29uc29sZS5pbmZvKFwid2lsbCBub3QgbG9nXCIpO1xufWVsc2V7XG4gIGNvbnNvbGUuaW5mbyhcIndpbGwgbG9nXCIpO1xufSIsIm9wdGlvbnMiOnsicGFyc2VyT3B0aW9ucyI6eyJlY21hVmVyc2lvbiI6Niwic291cmNlVHlwZSI6InNjcmlwdCIsImVjbWFGZWF0dXJlcyI6e319LCJydWxlcyI6e30sImVudiI6e319fQ==
I will take a look
I think thisPR (#12411) can fix it. Can I get a review? @platinumazure 
I realize that the schemes default value overrides user's configuration
It does seem that default values are causing this.

```js
const thisBefore = ("before" in override) ? override.before : before;
const thisAfter = ("after" in override) ? override.after : after;
```

`parseOptions` checks if the key (`"before"`/`"after"`) is present in the `overrides` object, but after the default values were introduced in #11288 both keys are always there.

It looks that the code was made to support merging overrides with the common settings. Removing default values could be the only way to restore this feature.

Though, this might be the only rule that was supposed to work like that? An alternative is to require complete configuration in the overrides object.
Tested the original example in:

eslint@5.13 - no error
eslint@5.14 - error

Seems that #11288 changed behavior here, but tests didn't catch that.

I think that proposed change in PR #12411 is correct, and it would be also good to add tests to show that overrides can override just `"before"` or just `"after"` or both. Maybe also improve the docs.

The problem might be that this change can now produce more warnings in some cases.



Patch:
diff --git a/lib/rules/keyword-spacing.js b/lib/rules/keyword-spacing.js
index ef619aa77917..2b3fef33bd7a 100644
--- a/lib/rules/keyword-spacing.js
+++ b/lib/rules/keyword-spacing.js
@@ -86,8 +86,8 @@ module.exports = {
                             retv[key] = {
                                 type: "object",
                                 properties: {
-                                    before: { type: "boolean", default: true },
-                                    after: { type: "boolean", default: true }
+                                    before: { type: "boolean" },
+                                    after: { type: "boolean" }
                                 },
                                 additionalProperties: false
                             };


Test patch:
diff --git a/tests/lib/rules/keyword-spacing.js b/tests/lib/rules/keyword-spacing.js
index 9c0bf8d0a69b..9971facf18cb 100644
--- a/tests/lib/rules/keyword-spacing.js
+++ b/tests/lib/rules/keyword-spacing.js
@@ -545,6 +545,8 @@ ruleTester.run("keyword-spacing", rule, {
         { code: "if (a) {}else{}", options: [override("else", NEITHER)] },
         "if (a) {}\nelse\n{}",
         { code: "if(a) {}\nelse\n{}", options: [NEITHER] },
+        { code: "if(a){ }else{ }", options: [{ before: false, after: true, overrides: { else: { after: false }, if: { after: false } } }] },
+        { code: "if(a){ }else{ }", options: [{ before: true, after: false, overrides: { else: { before: false }, if: { before: false } } }] },
 
         // not conflict with `semi-spacing`
         "if (a);else;",