2 * @fileoverview Enforce newlines between operands of ternary expressions
8 const astUtils
= require("./utils/ast-utils");
10 //------------------------------------------------------------------------------
12 //------------------------------------------------------------------------------
14 /** @type {import('../shared/types').Rule} */
20 description
: "Enforce newlines between operands of ternary expressions",
22 url
: "https://eslint.org/docs/rules/multiline-ternary"
27 enum: ["always", "always-multiline", "never"]
32 expectedTestCons
: "Expected newline between test and consequent of ternary expression.",
33 expectedConsAlt
: "Expected newline between consequent and alternate of ternary expression.",
34 unexpectedTestCons
: "Unexpected newline between test and consequent of ternary expression.",
35 unexpectedConsAlt
: "Unexpected newline between consequent and alternate of ternary expression."
42 const sourceCode
= context
.getSourceCode();
43 const option
= context
.options
[0];
44 const multiline
= option
!== "never";
45 const allowSingleLine
= option
=== "always-multiline";
47 //--------------------------------------------------------------------------
49 //--------------------------------------------------------------------------
52 ConditionalExpression(node
) {
53 const questionToken
= sourceCode
.getTokenAfter(node
.test
, astUtils
.isNotClosingParenToken
);
54 const colonToken
= sourceCode
.getTokenAfter(node
.consequent
, astUtils
.isNotClosingParenToken
);
56 const firstTokenOfTest
= sourceCode
.getFirstToken(node
);
57 const lastTokenOfTest
= sourceCode
.getTokenBefore(questionToken
);
58 const firstTokenOfConsequent
= sourceCode
.getTokenAfter(questionToken
);
59 const lastTokenOfConsequent
= sourceCode
.getTokenBefore(colonToken
);
60 const firstTokenOfAlternate
= sourceCode
.getTokenAfter(colonToken
);
62 const areTestAndConsequentOnSameLine
= astUtils
.isTokenOnSameLine(lastTokenOfTest
, firstTokenOfConsequent
);
63 const areConsequentAndAlternateOnSameLine
= astUtils
.isTokenOnSameLine(lastTokenOfConsequent
, firstTokenOfAlternate
);
65 const hasComments
= !!sourceCode
.getCommentsInside(node
).length
;
68 if (!areTestAndConsequentOnSameLine
) {
72 start
: firstTokenOfTest
.loc
.start
,
73 end
: lastTokenOfTest
.loc
.end
75 messageId
: "unexpectedTestCons",
81 const areTestAndQuestionOnSameLine
= astUtils
.isTokenOnSameLine(lastTokenOfTest
, questionToken
);
82 const areQuestionAndConsOnSameLine
= astUtils
.isTokenOnSameLine(questionToken
, firstTokenOfConsequent
);
84 if (!areTestAndQuestionOnSameLine
) {
85 fixers
.push(fixer
.removeRange([lastTokenOfTest
.range
[1], questionToken
.range
[0]]));
87 if (!areQuestionAndConsOnSameLine
) {
88 fixers
.push(fixer
.removeRange([questionToken
.range
[1], firstTokenOfConsequent
.range
[0]]));
96 if (!areConsequentAndAlternateOnSameLine
) {
98 node
: node
.consequent
,
100 start
: firstTokenOfConsequent
.loc
.start
,
101 end
: lastTokenOfConsequent
.loc
.end
103 messageId
: "unexpectedConsAlt",
109 const areConsAndColonOnSameLine
= astUtils
.isTokenOnSameLine(lastTokenOfConsequent
, colonToken
);
110 const areColonAndAltOnSameLine
= astUtils
.isTokenOnSameLine(colonToken
, firstTokenOfAlternate
);
112 if (!areConsAndColonOnSameLine
) {
113 fixers
.push(fixer
.removeRange([lastTokenOfConsequent
.range
[1], colonToken
.range
[0]]));
115 if (!areColonAndAltOnSameLine
) {
116 fixers
.push(fixer
.removeRange([colonToken
.range
[1], firstTokenOfAlternate
.range
[0]]));
124 if (allowSingleLine
&& node
.loc
.start
.line
=== node
.loc
.end
.line
) {
128 if (areTestAndConsequentOnSameLine
) {
132 start
: firstTokenOfTest
.loc
.start
,
133 end
: lastTokenOfTest
.loc
.end
135 messageId
: "expectedTestCons",
136 fix
: fixer
=> (hasComments
? null : (
137 fixer
.replaceTextRange(
139 lastTokenOfTest
.range
[1],
140 questionToken
.range
[0]
148 if (areConsequentAndAlternateOnSameLine
) {
150 node
: node
.consequent
,
152 start
: firstTokenOfConsequent
.loc
.start
,
153 end
: lastTokenOfConsequent
.loc
.end
155 messageId
: "expectedConsAlt",
156 fix
: (fixer
=> (hasComments
? null : (
157 fixer
.replaceTextRange(
159 lastTokenOfConsequent
.range
[1],