Repository: eslint/eslint (js)

Issue:
Ending line with &nbsp; breaks indent linting rules
<!--
    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 reporting a bug, please continue on. 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 change: https://eslint.org/docs/developer-guide/contributing/changes
    3. 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**

* **ESLint Version:**4.6.1
* **Node Version:**6.11.3
* **npm Version:**3.10.10

**What parser (default, Babel-ESLint, etc.) are you using?**
eslint, babel-eslint
**Please show your full configuration:**

<details>
<summary>Configuration</summary>

<!-- Paste your configuration below: -->
```js
{
  "extends": [
    "airbnb"
  ],
  "plugins": [
    "react",
    "import"
  ],
  "parser": "babel-eslint",
  "parserOptions": {
    "ecmaFeatures": {
      "jsx": true
    }
  },
  "env": {
    "es6": true,
    "browser": true,
    "node": true,
    "jest": true
  },
  "settings": {
    "import/resolver": "webpack"
  },
  "rules": {
    "jsx-a11y/label-has-for": [ 2, {
      "components": [ "Label" ],
      "required": {
        "some": [ "nesting", "id" ]
      },
      "allowChildren": false
    }],
    "arrow-body-style": 1,
    "arrow-parens": 0,
    "indent": [2, 2],
    "linebreak-style": [2, "unix"],
    "no-tabs": 2,
    "no-unused-expressions": 0,
    "semi": [2, "never"],
    "import/extensions": 0,
    "import/no-extraneous-dependencies": 0,
    "import/no-unresolved": 0,
    "import/prefer-default-export": 1,
    "jsx-a11y/href-no-hash": 2,
    "react/forbid-prop-types":   [2, { "forbid": ["any"] } ],
    "react/jsx-filename-extension": [2, { "extensions": [".js"] }],
    "react/jsx-indent": [2, 2]
  }
}
```

</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
            <small>By choosing to continue, you acknowledge you have reviewed our&nbsp;
              <a>information disclosure</a>.
            </small>
```

<!-- Paste the command you used to run ESLint: -->
```bash
eslint [folder]
```

**What did you expect to happen?**
The code above should pass indent linting rules.

**What actually happened? Please include the actual, raw output from ESLint.**
It generated the following error:

```bash
  62:1  error  Expected indentation of 12 spaces but found 14  indent
```

Removing two spaces generates the same error, inverted:

```bash
[eslint] Expected indentation of 14 space characters but found 12. 
```

However, moving the non-breaking space to the same line as the anchor tag, with 14 spaces, does not generate an error. It appears the line ending with the non-breaking space is breaking linting on the next line, at least partially (no other errors are generated). 

This works:
```js
            <small>By choosing to continue, you acknowledge you have reviewed our
              &nbsp;<a>information disclosure</a>.
            </small>
```

Pull request description:
Update: Correctly indent JSXText with trailing linebreaks (fixes #9878)
<!--
    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] Bug fix (https://github.com/eslint/eslint/issues/9878)

<!--
    If the item you've checked above has a template, please paste the template questions below and answer them. (If this pull request is addressing an issue, you can just paste a link to the issue here instead.)
-->

<!--
    Please ensure your pull request is ready:

    - Read the pull request guide (https://eslint.org/docs/developer-guide/contributing/pull-requests)
    - Include tests for this change
    - Update documentation for this change (if appropriate)
-->

<!--
    The following is required for all pull requests:
-->

**What changes did you make? (Give an overview)**

This fixes a bug in the `indent` rule where a line comparison with the end of a token would use the end location of any trailing whitespace in the token, rather than the location of the last non-whitespace character in the token. This behavior went against user intuition for tokens with trailing whitespace.

**Is there anything you'd like reviewers to focus on?**

Nothing in particular

Patch:
diff --git a/README.md b/README.md
index c333edd83..1f42b791c 100644
--- a/README.md
+++ b/README.md
@@ -227,9 +227,9 @@ In all cases, make sure your plugins' peerDependencies have been installed as we
 
 Yes, ESLint natively supports parsing JSX syntax (this must be enabled in [configuration](https://eslint.org/docs/user-guide/configuring)). Please note that supporting JSX syntax *is not* the same as supporting React. React applies specific semantics to JSX syntax that ESLint doesn't recognize. We recommend using [eslint-plugin-react](https://www.npmjs.com/package/eslint-plugin-react) if you are using React and want React semantics.
 
-### What about ECMAScript 6 support?
+### What ECMAScript versions does ESLint support?
 
-ESLint has full support for ECMAScript 6. By default, this support is off. You can enable ECMAScript 6 syntax and global variables through [configuration](https://eslint.org/docs/user-guide/configuring).
+ESLint has full support for ECMAScript 3, 5 (default), 2015, 2016, 2017, and 2018. You can set your desired ECMAScript syntax (and other settings, like global variables or your target environments) through [configuration](https://eslint.org/docs/user-guide/configuring).
 
 ### What about experimental features?
 
diff --git a/lib/rules/indent.js b/lib/rules/indent.js
index acc524630..faa42481b 100644
--- a/lib/rules/indent.js
+++ b/lib/rules/indent.js
@@ -779,6 +779,19 @@ module.exports = {
             return (statement.type === "ExpressionStatement" || statement.type === "VariableDeclaration") && statement.parent.type === "Program";
         }
 
+        /**
+         * Counts the number of linebreaks that follow the last non-whitespace character in a string
+         * @param {string} string The string to check
+         * @returns {number} The number of JavaScript linebreaks that follow the last non-whitespace character,
+         * or the total number of linebreaks if the string is all whitespace.
+         */
+        function countTrailingLinebreaks(string) {
+            const trailingWhitespace = string.match(/\s*$/)[0];
+            const linebreakMatches = trailingWhitespace.match(astUtils.createGlobalLinebreakMatcher());
+
+            return linebreakMatches === null ? 0 : linebreakMatches.length;
+        }
+
         /**
          * Check indentation for lists of elements (arrays, objects, function params)
          * @param {ASTNode[]} elements List of elements that should be offset
@@ -836,8 +849,12 @@ module.exports = {
                 } else {
                     const previousElement = elements[index - 1];
                     const firstTokenOfPreviousElement = previousElement && getFirstToken(previousElement);
+                    const previousElementLastToken = previousElement && sourceCode.getLastToken(previousElement);
 
-                    if (previousElement && sourceCode.getLastToken(previousElement).loc.end.line > startToken.loc.end.line) {
+                    if (
+                        previousElement &&
+                        previousElementLastToken.loc.end.line - countTrailingLinebreaks(previousElementLastToken.value) > startToken.loc.end.line
+                    ) {
                         offsets.setDesiredOffsets(element.range, firstTokenOfPreviousElement, 0);
                     }
                 }


Test patch:
diff --git a/tests/lib/rules/indent.js b/tests/lib/rules/indent.js
index 3a6bc0c99..92cfa2167 100644
--- a/tests/lib/rules/indent.js
+++ b/tests/lib/rules/indent.js
@@ -4607,6 +4607,16 @@ ruleTester.run("indent", rule, {
                     );
                 }
             `,
+        unIndent`
+            <div>foo
+                <div>bar</div>
+            </div>
+        `,
+        unIndent`
+            <small>Foo bar&nbsp;
+                <a>baz qux</a>.
+            </small>
+        `,
         {
             code: unIndent`
                 a(b
@@ -9136,6 +9146,32 @@ ruleTester.run("indent", rule, {
             `,
             errors: expectedErrors([3, 8, 6, "Block"])
         },
+        {
+            code: unIndent`
+                <div>foo
+                <div>bar</div>
+                </div>
+            `,
+            output: unIndent`
+                <div>foo
+                    <div>bar</div>
+                </div>
+            `,
+            errors: expectedErrors([2, 4, 0, "Punctuator"])
+        },
+        {
+            code: unIndent`
+                <small>Foo bar&nbsp;
+                <a>baz qux</a>.
+                </small>
+            `,
+            output: unIndent`
+                <small>Foo bar&nbsp;
+                    <a>baz qux</a>.
+                </small>
+            `,
+            errors: expectedErrors([2, 4, 0, "Punctuator"])
+        },
         {
             code: unIndent`
                 ({