Repository: eslint/eslint (js)

Issue:
flatTernaryExpressions does not work reliably
<!--
    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: http://eslint.org/docs/developer-guide/contributing/new-rules
    2. To request a change: http://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.0.0
* **Node Version:** 6.10.2
* **npm Version:** 5.4.1

**What parser (default, Babel-ESLint, etc.) are you using?** default

**Please show your full configuration:**

<details>
<summary>Configuration</summary>

<!-- Paste your configuration below: -->
```js
env:
  amd: true
  browser: true
  es6: true
  jquery: true
  node: true

# http://eslint.org/docs/rules/
rules:
  # Possible Errors
  no-cond-assign: 2
  no-console: [2, {allow: [warn, error]}]
  no-constant-condition: 2
  no-control-regex: 2
  no-debugger: 2
  no-dupe-args: 2
  no-dupe-keys: 2
  no-duplicate-case: 2
  no-empty: 2
  no-empty-character-class: 2
  no-ex-assign: 2
  no-extra-boolean-cast: 2
  no-extra-parens: [2, functions]
  no-extra-semi: 2
  no-func-assign: 2
  no-inner-declarations: [2, functions]
  no-invalid-regexp: 2
  no-irregular-whitespace: 2
  no-negated-in-lhs: 2
  no-obj-calls: 2
  no-regex-spaces: 2
  no-sparse-arrays: 2
  no-unexpected-multiline: 2
  no-unreachable: 2
  use-isnan: 2
  valid-jsdoc: 0
  valid-typeof: 2

  # Best Practices
  accessor-pairs: 2
  array-callback-return: 0
  block-scoped-var: 0
  complexity: [2, 10]
  consistent-return: 0
  curly: [2, all]
  default-case: 2
  dot-location: 0
  dot-notation: 2
  eqeqeq: 2
  guard-for-in: 2
  no-alert: 2
  no-caller: 2
  no-case-declarations: 2
  no-div-regex: 2
  no-else-return: 2
  no-empty-pattern: 2
  no-eq-null: 2
  no-eval: 2
  no-extend-native: 2
  no-extra-bind: 2
  no-fallthrough: 2
  no-floating-decimal: 2
  no-implicit-coercion: 0
  no-implied-eval: 2
  no-invalid-this: 0
  no-iterator: 2
  no-labels: 2
  no-lone-blocks: 2
  no-loop-func: 2
  no-magic-number: 0
  no-multi-spaces: [2, {ignoreEOLComments: true}]
  no-multi-str: 2
  no-native-reassign: 2
  no-new-func: 2
  no-new-wrappers: 2
  no-new: 2
  no-octal-escape: 2
  no-octal: 2
  no-proto: 2
  no-redeclare: 2
  no-return-assign: 2
  no-script-url: 2
  no-self-compare: 2
  no-sequences: 2
  no-throw-literal: 0
  no-unused-expressions: 2
  no-useless-call: 2
  no-useless-concat: 2
  no-void: 2
  no-warning-comments: 0
  no-with: 2
  radix: 2
  vars-on-top: 0
  wrap-iife: 2
  yoda: [1, never]

  # Strict
  strict: 0

  # Variables
  init-declarations: 0
  no-catch-shadow: 2
  no-delete-var: 2
  no-label-var: 2
  no-shadow-restricted-names: 2
  no-shadow: 2
  no-undef-init: 2
  no-undef: 2
  no-undefined: 0
  no-unused-vars: 2
  no-use-before-define: 2

  # Node.js and CommonJS
  callback-return: 2
  global-require: 2
  handle-callback-err: 2
  no-mixed-requires: 0
  no-new-require: 0
  no-path-concat: 2
  no-process-exit: 2
  no-restricted-modules: 0
  no-sync: 0

  # Stylistic Issues
  array-bracket-spacing: [2, never]
  block-spacing: 0
  brace-style: [2, 1tbs]
  camelcase: 2
  comma-dangle: [2, only-multiline]
  comma-spacing: 2
  comma-style: [2, last]
  computed-property-spacing: [2, never]
  consistent-this: [2, me]
  eol-last: 2
  func-call-spacing: 0
  func-names: [2, never]
  func-style: 0
  id-length: 0
  id-match: 0
  indent: [2, tab, {flatTernaryExpressions: true}]
  jsx-quotes: 0
  key-spacing: 2
  keyword-spacing: 2
  linebreak-style: 0
  lines-around-comment: 0
  max-depth: 0
  max-len: 0
  max-lines: 0
  max-nested-callbacks: 0
  max-params: 0
  max-statements-per-line: 0
  max-statements: [2, 30]
  multiline-ternary: 0
  new-cap: 0
  new-parens: 2
  newline-after-var: 0
  newline-before-return: 0
  newline-per-chained-call: 0
  no-array-constructor: 0
  no-bitwise: 0
  no-continue: 0
  no-inline-comments: 0
  no-lonely-if: 2
  no-mixed-operators: 0
  no-mixed-spaces-and-tabs: 2
  no-multiple-empty-lines: [2, {max: 2}]
  no-negated-condition: 0
  no-nested-ternary: 0
  no-new-object: 0
  no-plusplus: 0
  no-restricted-syntax: 0
  no-spaced-func: 0
  no-ternary: 0
  no-trailing-spaces: 2
  no-underscore-dangle: 0
  no-unneeded-ternary: 0
  no-whitespace-before-property: 2
  object-curly-newline: 0
  object-curly-spacing: [2, never]
  object-property-newline: 0
  one-var-declaration-per-line: 2
  one-var: [2, {initialized: never}]
  operator-assignment: 0
  operator-linebreak: 0
  padded-blocks: 0
  quote-props: [2, as-needed]
  quotes: [2, single, {avoidEscape: true}]
  require-jsdoc: 0
  semi-spacing: 2
  semi: [2, always]
  sort-keys: 0
  sort-vars: 0
  space-before-blocks: [2, always]
  space-before-function-paren: [2, never]
  space-in-parens: [2, never]
  space-infix-ops: 2
  space-unary-ops: [2, {words: true, nonwords: false}]
  spaced-comment: [2, always]
  unicode-bom: 0
  wrap-regex: 2

  # ECMAScript 6
  arrow-body-style: 0
  arrow-parens: 0
  arrow-spacing: 0
  constructor-super: 0
  generator-star-spacing: 0
  no-arrow-condition: 0
  no-class-assign: 0
  no-const-assign: 0
  no-dupe-class-members: 0
  no-this-before-super: 0
  no-var: 0
  object-shorthand: 0
  prefer-arrow-callback: 0
  prefer-const: 0
  prefer-reflect: 0
  prefer-spread: 0
  prefer-template: 0
  require-yield: 0
```

</details>

**What did you do? Please include the actual source code causing the issue.**

<!-- Paste the source code below: -->
```js
			return me.beginAtZero ? 0 :
				min < 0 && max < 0 ? max :
				min > 0 && max > 0 ? min :
				0;
```
Available here: https://github.com/chartjs/Chart.js/blob/master/src/core/core.scale.js#L595

**What did you expect to happen?**
I expect it to pass because I have `flatTernaryExpressions: true` in my `.eslintrc`
```js
indent: [2, tab, {flatTernaryExpressions: true}]
```

**What actually happened? Please include the actual, raw output from ESLint.**
>  619:1   error    Expected indentation of 3 tabs but found 4                           indent
  620:1   error    Expected indentation of 3 tabs but found 4                           indent
  621:1   error    Expected indentation of 3 tabs but found 4                           indent

It only passes if I wrap the code in parentheses:
```js
			return (me.beginAtZero ? 0 :
				min < 0 && max < 0 ? max :
				min > 0 && max > 0 ? min :
				0);
```


Pull request description:
Update: indent flatTernary option to handle `return` (fixes #9285)
<!--
    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)**

[ ] Documentation update
[x] Bug fix (https://github.com/eslint/eslint/issues/9285)
[ ] New rule ([template](https://raw.githubusercontent.com/eslint/eslint/master/templates/rule-proposal.md))
[ ] Changes an existing rule ([template](https://raw.githubusercontent.com/eslint/eslint/master/templates/rule-change-proposal.md))
[ ] Add autofixing to a rule
[ ] Add a CLI option
[ ] Add something to the core
[ ] Other, please explain:

<!--
    If the item you've checked above has a template, please paste the template questions below and answer them. (If this pull request is addressing an issue, you can just paste a link to the issue here instead.)
-->

<!--
    Please ensure your pull request is ready:

    - Read the pull request guide (http://eslint.org/docs/developer-guide/contributing/pull-requests)
    - Include tests for this change
    - Update documentation for this change (if appropriate)
-->

<!--
    The following is required for all pull requests:
-->

**What changes did you make? (Give an overview)**

This updates the `flatTernaryExpression` option of `indent` to check whether a ternary expression is on the same *line* as a statement, rather than checking if the expression itself starts the statement.

As a sidenote, it seems like it might be possible to create a reasonable checker for `BinaryExpression` and `LogicalExpression` nodes using this same heuristic.

**Is there anything you'd like reviewers to focus on?**

Does the updated behavior make sense? Are there cases where it doesn't work well?

Patch:
diff --git a/docs/rules/id-length.md b/docs/rules/id-length.md
index b63a88b08..a28407fec 100644
--- a/docs/rules/id-length.md
+++ b/docs/rules/id-length.md
@@ -192,7 +192,7 @@ data["y"] = 3;  // excused because of calculated property access
 Examples of **incorrect** code for this rule with the `{ "max": 10 }` option:
 
 ```js
-/*eslint id-length: ["error", { "max": "10" }]*/
+/*eslint id-length: ["error", { "max": 10 }]*/
 /*eslint-env es6*/
 
 var reallyLongVarName = 5;
@@ -210,7 +210,7 @@ try {
 Examples of **correct** code for this rule with the `{ "max": 10 }` option:
 
 ```js
-/*eslint id-length: ["error", { "max": "10" }]*/
+/*eslint id-length: ["error", { "max": 10 }]*/
 /*eslint-env es6*/
 
 var varName = 5;
diff --git a/docs/rules/no-restricted-globals.md b/docs/rules/no-restricted-globals.md
index c9df9d339..e3d612412 100644
--- a/docs/rules/no-restricted-globals.md
+++ b/docs/rules/no-restricted-globals.md
@@ -77,7 +77,7 @@ Examples of **incorrect** code for a sample `"event"` global variable name, alon
 
 ```js
 /*global event*/
-/* eslint no-restricted-globals: [{ name: "error", message: "Use local parameter instead." }] */
+/* eslint no-restricted-globals: ["error", { name: "error", message: "Use local parameter instead." }] */
 
 function onClick() {
     console.log(event);    // Unexpected global variable 'event'. Use local parameter instead.
diff --git a/lib/rules/indent.js b/lib/rules/indent.js
index 07aa1e830..0f6468a7e 100644
--- a/lib/rules/indent.js
+++ b/lib/rules/indent.js
@@ -950,12 +950,12 @@ module.exports = {
         }
 
         /**
-         * Check whether the given token is the first token of a statement.
+         * Check whether the given token is on the first line of a statement.
          * @param {Token} token The token to check.
          * @param {ASTNode} leafNode The expression node that the token belongs directly.
-         * @returns {boolean} `true` if the token is the first token of a statement.
+         * @returns {boolean} `true` if the token is on the first line of a statement.
          */
-        function isFirstTokenOfStatement(token, leafNode) {
+        function isOnFirstLineOfStatement(token, leafNode) {
             let node = leafNode;
 
             while (node.parent && !node.parent.type.endsWith("Statement") && !node.parent.type.endsWith("Declaration")) {
@@ -963,7 +963,7 @@ module.exports = {
             }
             node = node.parent;
 
-            return !node || node.range[0] === token.range[0];
+            return !node || node.loc.start.line === token.loc.start.line;
         }
 
         const baseOffsetListeners = {
@@ -1076,7 +1076,7 @@ module.exports = {
                 //     /*else*/ qiz ;
                 if (!options.flatTernaryExpressions ||
                     !astUtils.isTokenOnSameLine(node.test, node.consequent) ||
-                    isFirstTokenOfStatement(firstToken, node)
+                    isOnFirstLineOfStatement(firstToken, node)
                 ) {
                     const questionMarkToken = sourceCode.getFirstTokenBetween(node.test, node.consequent, token => token.type === "Punctuator" && token.value === "?");
                     const colonToken = sourceCode.getFirstTokenBetween(node.consequent, node.alternate, token => token.type === "Punctuator" && token.value === ":");
diff --git a/lib/rules/newline-per-chained-call.js b/lib/rules/newline-per-chained-call.js
index 613429d13..356c4baf3 100644
--- a/lib/rules/newline-per-chained-call.js
+++ b/lib/rules/newline-per-chained-call.js
@@ -19,7 +19,7 @@ module.exports = {
             category: "Stylistic Issues",
             recommended: false
         },
-
+        fixable: "whitespace",
         schema: [{
             type: "object",
             properties: {
@@ -40,6 +40,18 @@ module.exports = {
 
         const sourceCode = context.getSourceCode();
 
+        /**
+         * Get the prefix of a given MemberExpression node.
+         * If the MemberExpression node is a computed value it returns a
+         * left bracket. If not it returns a period.
+         *
+         * @param  {ASTNode} node - A MemberExpression node to get
+         * @returns {string} The prefix of the node.
+         */
+        function getPrefix(node) {
+            return node.computed ? "[" : ".";
+        }
+
         /**
          * Gets the property text of a given MemberExpression node.
          * If the text is multiline, this returns only the first line.
@@ -48,7 +60,7 @@ module.exports = {
          * @returns {string} The property text of the node.
          */
         function getPropertyText(node) {
-            const prefix = node.computed ? "[" : ".";
+            const prefix = getPrefix(node);
             const lines = sourceCode.getText(node.property).split(astUtils.LINEBREAK_MATCHER);
             const suffix = node.computed && lines.length === 1 ? "]" : "";
 
@@ -70,13 +82,18 @@ module.exports = {
                     parent = parent.callee.object;
                 }
 
-                if (depth > ignoreChainWithDepth && callee.property.loc.start.line === callee.object.loc.end.line) {
+                if (depth > ignoreChainWithDepth && astUtils.isTokenOnSameLine(callee.object, callee.property)) {
                     context.report({
                         node: callee.property,
                         loc: callee.property.loc.start,
                         message: "Expected line break before `{{callee}}`.",
                         data: {
                             callee: getPropertyText(callee)
+                        },
+                        fix(fixer) {
+                            const firstTokenAfterObject = sourceCode.getTokenAfter(callee.object, astUtils.isNotClosingParenToken);
+
+                            return fixer.insertTextBefore(firstTokenAfterObject, "\n");
                         }
                     });
                 }
diff --git a/lib/rules/no-undef-init.js b/lib/rules/no-undef-init.js
index 9df40e9ce..7e58f55a6 100644
--- a/lib/rules/no-undef-init.js
+++ b/lib/rules/no-undef-init.js
@@ -43,6 +43,10 @@ module.exports = {
                         message: "It's not necessary to initialize '{{name}}' to undefined.",
                         data: { name },
                         fix(fixer) {
+                            if (node.parent.kind === "var") {
+                                return null;
+                            }
+
                             if (node.id.type === "ArrayPattern" || node.id.type === "ObjectPattern") {
 
                                 // Don't fix destructuring assignment to `undefined`.


Test patch:
diff --git a/tests/lib/rules/indent.js b/tests/lib/rules/indent.js
index 1339c16f6..006d7f1dd 100644
--- a/tests/lib/rules/indent.js
+++ b/tests/lib/rules/indent.js
@@ -3591,6 +3591,31 @@ ruleTester.run("indent", rule, {
             `,
             options: [4, { flatTernaryExpressions: true }]
         },
+        {
+            code: unIndent`
+                function foo() {
+                    return foo ? bar :
+                        baz
+                }
+            `,
+            options: [4, { flatTernaryExpressions: true }]
+        },
+        {
+            code: unIndent`
+                throw foo ? bar :
+                    baz
+            `,
+            options: [4, { flatTernaryExpressions: true }]
+        },
+        {
+            code: unIndent`
+                foo(
+                    bar
+                ) ? baz :
+                    qux
+            `,
+            options: [4, { flatTernaryExpressions: true }]
+        },
         unIndent`
                 foo
                     [
diff --git a/tests/lib/rules/newline-per-chained-call.js b/tests/lib/rules/newline-per-chained-call.js
index 232aafed6..ada18a70b 100644
--- a/tests/lib/rules/newline-per-chained-call.js
+++ b/tests/lib/rules/newline-per-chained-call.js
@@ -28,6 +28,7 @@ ruleTester.run("newline-per-chained-call", rule, {
     }],
     invalid: [{
         code: "_\n.chain({}).map(foo).filter(bar).value();",
+        output: "_\n.chain({}).map(foo)\n.filter(bar)\n.value();",
         errors: [{
             message: "Expected line break before `.filter`."
         }, {
@@ -35,26 +36,31 @@ ruleTester.run("newline-per-chained-call", rule, {
         }]
     }, {
         code: "_\n.chain({})\n.map(foo)\n.filter(bar).value();",
+        output: "_\n.chain({})\n.map(foo)\n.filter(bar)\n.value();",
         errors: [{
             message: "Expected line break before `.value`."
         }]
     }, {
         code: "a().b().c().e.d()",
+        output: "a().b()\n.c().e.d()",
         errors: [{
             message: "Expected line break before `.c`."
         }]
     }, {
         code: "a.b.c().e().d()",
+        output: "a.b.c().e()\n.d()",
         errors: [{
             message: "Expected line break before `.d`."
         }]
     }, {
         code: "_.chain({}).map(a).value(); ",
+        output: "_.chain({}).map(a)\n.value(); ",
         errors: [{
             message: "Expected line break before `.value`."
         }]
     }, {
         code: "var a = m1.m2();\n var b = m1.m2().m3().m4().m5();",
+        output: "var a = m1.m2();\n var b = m1.m2().m3()\n.m4()\n.m5();",
         errors: [{
             message: "Expected line break before `.m4`."
         }, {
@@ -62,11 +68,13 @@ ruleTester.run("newline-per-chained-call", rule, {
         }]
     }, {
         code: "var a = m1.m2();\n var b = m1.m2().m3()\n.m4().m5();",
+        output: "var a = m1.m2();\n var b = m1.m2().m3()\n.m4()\n.m5();",
         errors: [{
             message: "Expected line break before `.m5`."
         }]
     }, {
         code: "var a = m1().m2\n.m3().m4().m5().m6().m7();",
+        output: "var a = m1().m2\n.m3().m4().m5()\n.m6()\n.m7();",
         options: [{
             ignoreChainWithDepth: 3
         }],
@@ -105,6 +113,37 @@ ruleTester.run("newline-per-chained-call", rule, {
             "    // Do something with error.",
             "}).end();"
         ].join("\n"),
+        output: [
+            "http.request({",
+            "    // Param",
+            "    // Param",
+            "    // Param",
+            "}).on('response', function(response) {",
+            "    // Do something with response.",
+            "    // Do something with response.",
+            "    // Do something with response.",
+            "    // Do something with response.",
+            "    // Do something with response.",
+            "    // Do something with response.",
+            "    // Do something with response.",
+            "    // Do something with response.",
+            "    // Do something with response.",
+            "    // Do something with response.",
+            "})",
+            ".on('error', function(error) {",
+            "    // Do something with error.",
+            "    // Do something with error.",
+            "    // Do something with error.",
+            "    // Do something with error.",
+            "    // Do something with error.",
+            "    // Do something with error.",
+            "    // Do something with error.",
+            "    // Do something with error.",
+            "    // Do something with error.",
+            "    // Do something with error.",
+            "})",
+            ".end();"
+        ].join("\n"),
         errors: [{
             message: "Expected line break before `.on`."
         }, {
@@ -116,6 +155,13 @@ ruleTester.run("newline-per-chained-call", rule, {
             "    'method3' :",
             "    'method4']()"
         ].join("\n"),
+        output: [
+            "anObject.method1().method2()",
+            "['method' + n]()",
+            "[aCondition ?",
+            "    'method3' :",
+            "    'method4']()"
+        ].join("\n"),
         errors: [{
             message: "Expected line break before `['method' + n]`."
         }, {
@@ -123,8 +169,28 @@ ruleTester.run("newline-per-chained-call", rule, {
         }]
     }, {
         code: "foo.bar()['foo' + \u2029 + 'bar']()",
+        output: "foo.bar()\n['foo' + \u2029 + 'bar']()",
         options: [{ ignoreChainWithDepth: 1 }],
         errors: [{ message: "Expected line break before `['foo' + `." }]
+    }, {
+        code: "foo.bar()[(biz)]()",
+        output: "foo.bar()\n[(biz)]()",
+        options: [{ ignoreChainWithDepth: 1 }],
+        errors: [{ message: "Expected line break before `[biz]`." }]
+    }, {
+        code: "(foo).bar().biz()",
+        output: "(foo).bar()\n.biz()",
+        options: [{ ignoreChainWithDepth: 1 }],
+        errors: [{ message: "Expected line break before `.biz`." }]
+    }, {
+        code: "foo.bar(). /* comment */ biz()",
+        output: "foo.bar()\n. /* comment */ biz()",
+        options: [{ ignoreChainWithDepth: 1 }],
+        errors: [{ message: "Expected line break before `.biz`." }]
+    }, {
+        code: "foo.bar() /* comment */ .biz()",
+        output: "foo.bar() /* comment */ \n.biz()",
+        options: [{ ignoreChainWithDepth: 1 }],
+        errors: [{ message: "Expected line break before `.biz`." }]
     }]
-
 });
diff --git a/tests/lib/rules/no-undef-init.js b/tests/lib/rules/no-undef-init.js
index 2d44e1656..dfd45e008 100644
--- a/tests/lib/rules/no-undef-init.js
+++ b/tests/lib/rules/no-undef-init.js
@@ -27,17 +27,17 @@ ruleTester.run("no-undef-init", rule, {
     invalid: [
         {
             code: "var a = undefined;",
-            output: "var a;",
+            output: null,
             errors: [{ message: "It's not necessary to initialize 'a' to undefined.", type: "VariableDeclarator" }]
         },
         {
             code: "var a = undefined, b = 1;",
-            output: "var a, b = 1;",
+            output: null,
             errors: [{ message: "It's not necessary to initialize 'a' to undefined.", type: "VariableDeclarator" }]
         },
         {
             code: "var a = 1, b = undefined, c = 5;",
-            output: "var a = 1, b, c = 5;",
+            output: null,
             errors: [{ message: "It's not necessary to initialize 'b' to undefined.", type: "VariableDeclarator" }]
         },
         {
@@ -51,6 +51,47 @@ ruleTester.run("no-undef-init", rule, {
             output: null,
             parserOptions: { ecmaVersion: 6 },
             errors: [{ message: "It's not necessary to initialize '{a}' to undefined.", type: "VariableDeclarator" }]
+        },
+        {
+            code: "for(var i in [1,2,3]){var a = undefined; for(var j in [1,2,3]){}}",
+            output: null,
+            errors: [{ message: "It's not necessary to initialize 'a' to undefined.", type: "VariableDeclarator" }]
+        },
+        {
+            code: "let a = undefined;",
+            output: "let a;",
+            parserOptions: { ecmaVersion: 6 },
+            errors: [{ message: "It's not necessary to initialize 'a' to undefined.", type: "VariableDeclarator" }]
+        },
+        {
+            code: "let a = undefined, b = 1;",
+            output: "let a, b = 1;",
+            parserOptions: { ecmaVersion: 6 },
+            errors: [{ message: "It's not necessary to initialize 'a' to undefined.", type: "VariableDeclarator" }]
+        },
+        {
+            code: "let a = 1, b = undefined, c = 5;",
+            output: "let a = 1, b, c = 5;",
+            parserOptions: { ecmaVersion: 6 },
+            errors: [{ message: "It's not necessary to initialize 'b' to undefined.", type: "VariableDeclarator" }]
+        },
+        {
+            code: "let [a] = undefined;",
+            output: null,
+            parserOptions: { ecmaVersion: 6 },
+            errors: [{ message: "It's not necessary to initialize '[a]' to undefined.", type: "VariableDeclarator" }]
+        },
+        {
+            code: "let {a} = undefined;",
+            output: null,
+            parserOptions: { ecmaVersion: 6 },
+            errors: [{ message: "It's not necessary to initialize '{a}' to undefined.", type: "VariableDeclarator" }]
+        },
+        {
+            code: "for(var i in [1,2,3]){let a = undefined; for(var j in [1,2,3]){}}",
+            output: "for(var i in [1,2,3]){let a; for(var j in [1,2,3]){}}",
+            parserOptions: { ecmaVersion: 6 },
+            errors: [{ message: "It's not necessary to initialize 'a' to undefined.", type: "VariableDeclarator" }]
         }
     ]
 });