diff --git a/lib/rules/multiline-ternary.js b/lib/rules/multiline-ternary.js index 6668bff4824..98360b9cad4 100644 --- a/lib/rules/multiline-ternary.js +++ b/lib/rules/multiline-ternary.js @@ -27,19 +27,22 @@ module.exports = { enum: ["always", "always-multiline", "never"] } ], + messages: { expectedTestCons: "Expected newline between test and consequent of ternary expression.", expectedConsAlt: "Expected newline between consequent and alternate of ternary expression.", unexpectedTestCons: "Unexpected newline between test and consequent of ternary expression.", unexpectedConsAlt: "Unexpected newline between consequent and alternate of ternary expression." - } + }, + + fixable: "whitespace" }, create(context) { + const sourceCode = context.getSourceCode(); const option = context.options[0]; const multiline = option !== "never"; const allowSingleLine = option === "always-multiline"; - const sourceCode = context.getSourceCode(); //-------------------------------------------------------------------------- // Public @@ -59,6 +62,8 @@ module.exports = { const areTestAndConsequentOnSameLine = astUtils.isTokenOnSameLine(lastTokenOfTest, firstTokenOfConsequent); const areConsequentAndAlternateOnSameLine = astUtils.isTokenOnSameLine(lastTokenOfConsequent, firstTokenOfAlternate); + const hasComments = !!sourceCode.getCommentsInside(node).length; + if (!multiline) { if (!areTestAndConsequentOnSameLine) { context.report({ @@ -67,7 +72,24 @@ module.exports = { start: firstTokenOfTest.loc.start, end: lastTokenOfTest.loc.end }, - messageId: "unexpectedTestCons" + messageId: "unexpectedTestCons", + fix: fixer => { + if (hasComments) { + return null; + } + const fixers = []; + const areTestAndQuestionOnSameLine = astUtils.isTokenOnSameLine(lastTokenOfTest, questionToken); + const areQuestionAndConsOnSameLine = astUtils.isTokenOnSameLine(questionToken, firstTokenOfConsequent); + + if (!areTestAndQuestionOnSameLine) { + fixers.push(fixer.removeRange([lastTokenOfTest.range[1], questionToken.range[0]])); + } + if (!areQuestionAndConsOnSameLine) { + fixers.push(fixer.removeRange([questionToken.range[1], firstTokenOfConsequent.range[0]])); + } + + return fixers; + } }); } @@ -78,7 +100,24 @@ module.exports = { start: firstTokenOfConsequent.loc.start, end: lastTokenOfConsequent.loc.end }, - messageId: "unexpectedConsAlt" + messageId: "unexpectedConsAlt", + fix: fixer => { + if (hasComments) { + return null; + } + const fixers = []; + const areConsAndColonOnSameLine = astUtils.isTokenOnSameLine(lastTokenOfConsequent, colonToken); + const areColonAndAltOnSameLine = astUtils.isTokenOnSameLine(colonToken, firstTokenOfAlternate); + + if (!areConsAndColonOnSameLine) { + fixers.push(fixer.removeRange([lastTokenOfConsequent.range[1], colonToken.range[0]])); + } + if (!areColonAndAltOnSameLine) { + fixers.push(fixer.removeRange([colonToken.range[1], firstTokenOfAlternate.range[0]])); + } + + return fixers; + } }); } } else { @@ -93,7 +132,16 @@ module.exports = { start: firstTokenOfTest.loc.start, end: lastTokenOfTest.loc.end }, - messageId: "expectedTestCons" + messageId: "expectedTestCons", + fix: fixer => (hasComments ? null : ( + fixer.replaceTextRange( + [ + lastTokenOfTest.range[1], + questionToken.range[0] + ], + "\n" + ) + )) }); } @@ -104,7 +152,16 @@ module.exports = { start: firstTokenOfConsequent.loc.start, end: lastTokenOfConsequent.loc.end }, - messageId: "expectedConsAlt" + messageId: "expectedConsAlt", + fix: (fixer => (hasComments ? null : ( + fixer.replaceTextRange( + [ + lastTokenOfConsequent.range[1], + colonToken.range[0] + ], + "\n" + ) + ))) }); } } diff --git a/tests/lib/rules/multiline-ternary.js b/tests/lib/rules/multiline-ternary.js index ff0f9d1535d..04698ae9513 100644 --- a/tests/lib/rules/multiline-ternary.js +++ b/tests/lib/rules/multiline-ternary.js @@ -116,6 +116,7 @@ ruleTester.run("multiline-ternary", rule, { // default "always" { code: "a ? b : c", + output: "a\n? b\n: c", errors: [{ messageId: "expectedTestCons", line: 1, @@ -129,6 +130,7 @@ ruleTester.run("multiline-ternary", rule, { }, { code: "a\n? b : c", + output: "a\n? b\n: c", errors: [{ messageId: "expectedConsAlt", line: 2, @@ -137,6 +139,7 @@ ruleTester.run("multiline-ternary", rule, { }, { code: "a ? b\n: c", + output: "a\n? b\n: c", errors: [{ messageId: "expectedTestCons", line: 1, @@ -145,6 +148,7 @@ ruleTester.run("multiline-ternary", rule, { }, { code: "a ? (b ? c : d) : e", + output: "a\n? (b\n? c\n: d)\n: e", errors: [{ messageId: "expectedTestCons", line: 1, @@ -170,6 +174,7 @@ ruleTester.run("multiline-ternary", rule, { }, { code: "a ?\n(b ? c : d) :\ne", + output: "a ?\n(b\n? c\n: d) :\ne", errors: [{ messageId: "expectedTestCons", line: 2, @@ -183,6 +188,7 @@ ruleTester.run("multiline-ternary", rule, { }, { code: "a ? (b\n? c\n: d) : e", + output: "a\n? (b\n? c\n: d)\n: e", errors: [{ messageId: "expectedTestCons", line: 1, @@ -198,6 +204,7 @@ ruleTester.run("multiline-ternary", rule, { }, { code: "a ?\n(b? c\n: d) : e", + output: "a ?\n(b\n? c\n: d)\n: e", errors: [{ messageId: "expectedConsAlt", line: 2, @@ -213,6 +220,7 @@ ruleTester.run("multiline-ternary", rule, { }, { code: "a ?\n(b\n? c : d) : e", + output: "a ?\n(b\n? c\n: d)\n: e", errors: [{ messageId: "expectedConsAlt", line: 2, @@ -228,6 +236,7 @@ ruleTester.run("multiline-ternary", rule, { }, { code: "a ?\n(b\n? c\n : d) : e", + output: "a ?\n(b\n? c\n : d)\n: e", errors: [{ messageId: "expectedConsAlt", line: 2, @@ -240,6 +249,7 @@ ruleTester.run("multiline-ternary", rule, { // "always" { code: "a ? b : c", + output: "a\n? b\n: c", options: ["always"], errors: [{ messageId: "expectedTestCons", @@ -258,6 +268,7 @@ ruleTester.run("multiline-ternary", rule, { }, { code: "f() ? a + b : c", + output: "f()\n? a + b\n: c", options: ["always"], errors: [{ messageId: "expectedTestCons", @@ -276,6 +287,7 @@ ruleTester.run("multiline-ternary", rule, { }, { code: "a\n? b : c", + output: "a\n? b\n: c", options: ["always"], errors: [{ messageId: "expectedConsAlt", @@ -285,6 +297,7 @@ ruleTester.run("multiline-ternary", rule, { }, { code: "a ? b\n: c", + output: "a\n? b\n: c", options: ["always"], errors: [{ messageId: "expectedTestCons", @@ -294,6 +307,7 @@ ruleTester.run("multiline-ternary", rule, { }, { code: "a ? (b ? c : d) : e", + output: "a\n? (b\n? c\n: d)\n: e", options: ["always"], errors: [{ messageId: "expectedTestCons", @@ -320,6 +334,7 @@ ruleTester.run("multiline-ternary", rule, { }, { code: "a ?\n(b ? c : d) :\ne", + output: "a ?\n(b\n? c\n: d) :\ne", options: ["always"], errors: [{ messageId: "expectedTestCons", @@ -334,6 +349,7 @@ ruleTester.run("multiline-ternary", rule, { }, { code: "a ? (b\n? c\n: d) : e", + output: "a\n? (b\n? c\n: d)\n: e", options: ["always"], errors: [{ messageId: "expectedTestCons", @@ -350,6 +366,7 @@ ruleTester.run("multiline-ternary", rule, { }, { code: "a ?\n(b? c\n: d) : e", + output: "a ?\n(b\n? c\n: d)\n: e", options: ["always"], errors: [{ messageId: "expectedConsAlt", @@ -366,6 +383,7 @@ ruleTester.run("multiline-ternary", rule, { }, { code: "a ?\n(b\n? c : d) : e", + output: "a ?\n(b\n? c\n: d)\n: e", options: ["always"], errors: [{ messageId: "expectedConsAlt", @@ -382,6 +400,7 @@ ruleTester.run("multiline-ternary", rule, { }, { code: "a ?\n(b\n? c\n : d) : e", + output: "a ?\n(b\n? c\n : d)\n: e", options: ["always"], errors: [{ messageId: "expectedConsAlt", @@ -393,6 +412,7 @@ ruleTester.run("multiline-ternary", rule, { }, { code: "(a\n) ? b\n: c", + output: "(a\n)\n? b\n: c", options: ["always"], errors: [{ messageId: "expectedTestCons", @@ -404,6 +424,7 @@ ruleTester.run("multiline-ternary", rule, { }, { code: "((a)\n) ? b\n: c", + output: "((a)\n)\n? b\n: c", options: ["always"], errors: [{ messageId: "expectedTestCons", @@ -415,6 +436,7 @@ ruleTester.run("multiline-ternary", rule, { }, { code: "a ? (\nb)\n: c", + output: "a\n? (\nb)\n: c", options: ["always"], errors: [{ messageId: "expectedTestCons", @@ -426,6 +448,7 @@ ruleTester.run("multiline-ternary", rule, { }, { code: "a ? (\n(b))\n: c", + output: "a\n? (\n(b))\n: c", options: ["always"], errors: [{ messageId: "expectedTestCons", @@ -437,6 +460,7 @@ ruleTester.run("multiline-ternary", rule, { }, { code: "a\n? (b\n): c", + output: "a\n? (b\n)\n: c", options: ["always"], errors: [{ messageId: "expectedConsAlt", @@ -448,6 +472,7 @@ ruleTester.run("multiline-ternary", rule, { }, { code: "a\n? ((b)\n): c", + output: "a\n? ((b)\n)\n: c", options: ["always"], errors: [{ messageId: "expectedConsAlt", @@ -459,6 +484,7 @@ ruleTester.run("multiline-ternary", rule, { }, { code: "a\n? b : (\nc)", + output: "a\n? b\n: (\nc)", options: ["always"], errors: [{ messageId: "expectedConsAlt", @@ -470,6 +496,7 @@ ruleTester.run("multiline-ternary", rule, { }, { code: "a\n? b : (\n(c))", + output: "a\n? b\n: (\n(c))", options: ["always"], errors: [{ messageId: "expectedConsAlt", @@ -481,6 +508,7 @@ ruleTester.run("multiline-ternary", rule, { }, { code: "(a\n) ? (\nb\n) : (\nc)", + output: "(a\n)\n? (\nb\n)\n: (\nc)", options: ["always"], errors: [{ messageId: "expectedTestCons", @@ -499,6 +527,7 @@ ruleTester.run("multiline-ternary", rule, { }, { code: "((a)\n) ? (\n(b)\n) : (\n(c))", + output: "((a)\n)\n? (\n(b)\n)\n: (\n(c))", options: ["always"], errors: [{ messageId: "expectedTestCons", @@ -519,6 +548,7 @@ ruleTester.run("multiline-ternary", rule, { // "always-multiline" { code: "a\n? b : c", + output: "a\n? b\n: c", options: ["always-multiline"], errors: [{ messageId: "expectedConsAlt", @@ -528,6 +558,7 @@ ruleTester.run("multiline-ternary", rule, { }, { code: "a ? b\n: c", + output: "a\n? b\n: c", options: ["always-multiline"], errors: [{ messageId: "expectedTestCons", @@ -537,6 +568,7 @@ ruleTester.run("multiline-ternary", rule, { }, { code: "a &&\nb ? c : d", + output: "a &&\nb\n? c\n: d", options: ["always-multiline"], errors: [{ messageId: "expectedTestCons", @@ -553,6 +585,7 @@ ruleTester.run("multiline-ternary", rule, { }, { code: "a ? b +\nc : d", + output: "a\n? b +\nc\n: d", options: ["always-multiline"], errors: [{ messageId: "expectedTestCons", @@ -567,6 +600,7 @@ ruleTester.run("multiline-ternary", rule, { }, { code: "a ? b : c +\nd", + output: "a\n? b\n: c +\nd", options: ["always-multiline"], errors: [{ messageId: "expectedTestCons", @@ -581,6 +615,7 @@ ruleTester.run("multiline-ternary", rule, { }, { code: "a ?\n(b ? c : d) : e", + output: "a ?\n(b ? c : d)\n: e", options: ["always-multiline"], errors: [{ messageId: "expectedConsAlt", @@ -592,6 +627,7 @@ ruleTester.run("multiline-ternary", rule, { }, { code: "a ? (b ? c : d) :\ne", + output: "a\n? (b ? c : d) :\ne", options: ["always-multiline"], errors: [{ messageId: "expectedTestCons", @@ -601,6 +637,7 @@ ruleTester.run("multiline-ternary", rule, { }, { code: "a ? (b\n? c\n: d) : e", + output: "a\n? (b\n? c\n: d)\n: e", options: ["always-multiline"], errors: [{ messageId: "expectedTestCons", @@ -617,6 +654,7 @@ ruleTester.run("multiline-ternary", rule, { }, { code: "a ?\n(b ? c\n: d) : e", + output: "a ?\n(b\n? c\n: d)\n: e", options: ["always-multiline"], errors: [{ messageId: "expectedConsAlt", @@ -633,6 +671,7 @@ ruleTester.run("multiline-ternary", rule, { }, { code: "a ?\n(b\n? c : d) : e", + output: "a ?\n(b\n? c\n: d)\n: e", options: ["always-multiline"], errors: [{ messageId: "expectedConsAlt", @@ -649,6 +688,7 @@ ruleTester.run("multiline-ternary", rule, { }, { code: "a ?\n(b\n? c\n : d) : e", + output: "a ?\n(b\n? c\n : d)\n: e", options: ["always-multiline"], errors: [{ messageId: "expectedConsAlt", @@ -660,6 +700,7 @@ ruleTester.run("multiline-ternary", rule, { }, { code: "(a\n) ? b\n: c", + output: "(a\n)\n? b\n: c", options: ["always-multiline"], errors: [{ messageId: "expectedTestCons", @@ -671,6 +712,7 @@ ruleTester.run("multiline-ternary", rule, { }, { code: "((a)\n) ? b\n: c", + output: "((a)\n)\n? b\n: c", options: ["always-multiline"], errors: [{ messageId: "expectedTestCons", @@ -682,6 +724,7 @@ ruleTester.run("multiline-ternary", rule, { }, { code: "a ? (\nb)\n: c", + output: "a\n? (\nb)\n: c", options: ["always-multiline"], errors: [{ messageId: "expectedTestCons", @@ -693,6 +736,7 @@ ruleTester.run("multiline-ternary", rule, { }, { code: "a ? (\n(b))\n: c", + output: "a\n? (\n(b))\n: c", options: ["always-multiline"], errors: [{ messageId: "expectedTestCons", @@ -704,6 +748,7 @@ ruleTester.run("multiline-ternary", rule, { }, { code: "a\n? (b\n): c", + output: "a\n? (b\n)\n: c", options: ["always-multiline"], errors: [{ messageId: "expectedConsAlt", @@ -715,6 +760,7 @@ ruleTester.run("multiline-ternary", rule, { }, { code: "a\n? ((b)\n): c", + output: "a\n? ((b)\n)\n: c", options: ["always-multiline"], errors: [{ messageId: "expectedConsAlt", @@ -726,6 +772,7 @@ ruleTester.run("multiline-ternary", rule, { }, { code: "a\n? b : (\nc)", + output: "a\n? b\n: (\nc)", options: ["always-multiline"], errors: [{ messageId: "expectedConsAlt", @@ -737,6 +784,7 @@ ruleTester.run("multiline-ternary", rule, { }, { code: "a\n? b : (\n(c))", + output: "a\n? b\n: (\n(c))", options: ["always-multiline"], errors: [{ messageId: "expectedConsAlt", @@ -748,6 +796,7 @@ ruleTester.run("multiline-ternary", rule, { }, { code: "(a\n) ? (\nb\n) : (\nc)", + output: "(a\n)\n? (\nb\n)\n: (\nc)", options: ["always-multiline"], errors: [{ messageId: "expectedTestCons", @@ -766,6 +815,7 @@ ruleTester.run("multiline-ternary", rule, { }, { code: "((a)\n) ? (\n(b)\n) : (\n(c))", + output: "((a)\n)\n? (\n(b)\n)\n: (\n(c))", options: ["always-multiline"], errors: [{ messageId: "expectedTestCons", @@ -786,6 +836,7 @@ ruleTester.run("multiline-ternary", rule, { // "never" { code: "a\n? b : c", + output: "a? b : c", options: ["never"], errors: [{ messageId: "unexpectedTestCons", @@ -795,6 +846,7 @@ ruleTester.run("multiline-ternary", rule, { }, { code: "a ? b\n: c", + output: "a ? b: c", options: ["never"], errors: [{ messageId: "unexpectedConsAlt", @@ -804,6 +856,7 @@ ruleTester.run("multiline-ternary", rule, { }, { code: "a ?\n(b ? c : d) :\ne", + output: "a ?(b ? c : d) :e", options: ["never"], errors: [{ messageId: "unexpectedTestCons", @@ -820,6 +873,7 @@ ruleTester.run("multiline-ternary", rule, { }, { code: "a ? (b\n? c\n: d) : e", + output: "a ? (b? c: d) : e", options: ["never"], errors: [{ messageId: "unexpectedTestCons", @@ -834,6 +888,7 @@ ruleTester.run("multiline-ternary", rule, { }, { code: "a ?\n(b? c\n: d) : e", + output: "a ?(b? c: d) : e", options: ["never"], errors: [{ messageId: "unexpectedTestCons", @@ -848,6 +903,7 @@ ruleTester.run("multiline-ternary", rule, { }, { code: "a ?\n(b\n? c : d) : e", + output: "a ?(b? c : d) : e", options: ["never"], errors: [{ messageId: "unexpectedTestCons", @@ -862,6 +918,7 @@ ruleTester.run("multiline-ternary", rule, { }, { code: "a ?\n(b\n? c\n : d) : e", + output: "a ?(b? c: d) : e", options: ["never"], errors: [{ messageId: "unexpectedTestCons", @@ -881,6 +938,7 @@ ruleTester.run("multiline-ternary", rule, { }, { code: "a ? (b\n? c\n: d)\n: e", + output: "a ? (b? c: d): e", options: ["never"], errors: [{ messageId: "unexpectedConsAlt", @@ -902,6 +960,7 @@ ruleTester.run("multiline-ternary", rule, { }, { code: "a\n?\n(b\n?\nc\n:\nd)\n:\ne", + output: "a?(b?c:d):e", options: ["never"], errors: [{ messageId: "unexpectedTestCons", @@ -928,6 +987,7 @@ ruleTester.run("multiline-ternary", rule, { }, { code: "(a)\n ? b \n : (c)", + output: "(a)? b: (c)", options: ["never"], errors: [{ messageId: "unexpectedTestCons", @@ -946,6 +1006,7 @@ ruleTester.run("multiline-ternary", rule, { }, { code: "(a)\n ? (b) \n : (c)", + output: "(a)? (b): (c)", options: ["never"], errors: [{ messageId: "unexpectedTestCons", @@ -964,6 +1025,7 @@ ruleTester.run("multiline-ternary", rule, { }, { code: "((a))\n ? ((b)) \n : ((c))", + output: "((a))? ((b)): ((c))", options: ["never"], errors: [{ messageId: "unexpectedTestCons", @@ -979,6 +1041,15 @@ ruleTester.run("multiline-ternary", rule, { endLine: 2, endColumn: 9 }] + }, + + // https://github.com/eslint/eslint/pull/12982#discussion_r409120960 + { + code: "a ? // comment\nb : c;", + output: null, + errors: [{ + messageId: "expectedConsAlt" + }] } ] });