Skip to content
Permalink
9bfb9ba527
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
171 lines (149 sloc) 7.54 KB
/**
* @fileoverview Enforce newlines between operands of ternary expressions
* @author Kai Cataldo
*/
"use strict";
const astUtils = require("./utils/ast-utils");
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
/** @type {import('../shared/types').Rule} */
module.exports = {
meta: {
type: "layout",
docs: {
description: "Enforce newlines between operands of ternary expressions",
recommended: false,
url: "https://eslint.org/docs/latest/rules/multiline-ternary"
},
schema: [
{
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.sourceCode;
const option = context.options[0];
const multiline = option !== "never";
const allowSingleLine = option === "always-multiline";
//--------------------------------------------------------------------------
// Public
//--------------------------------------------------------------------------
return {
ConditionalExpression(node) {
const questionToken = sourceCode.getTokenAfter(node.test, astUtils.isNotClosingParenToken);
const colonToken = sourceCode.getTokenAfter(node.consequent, astUtils.isNotClosingParenToken);
const firstTokenOfTest = sourceCode.getFirstToken(node);
const lastTokenOfTest = sourceCode.getTokenBefore(questionToken);
const firstTokenOfConsequent = sourceCode.getTokenAfter(questionToken);
const lastTokenOfConsequent = sourceCode.getTokenBefore(colonToken);
const firstTokenOfAlternate = sourceCode.getTokenAfter(colonToken);
const areTestAndConsequentOnSameLine = astUtils.isTokenOnSameLine(lastTokenOfTest, firstTokenOfConsequent);
const areConsequentAndAlternateOnSameLine = astUtils.isTokenOnSameLine(lastTokenOfConsequent, firstTokenOfAlternate);
const hasComments = !!sourceCode.getCommentsInside(node).length;
if (!multiline) {
if (!areTestAndConsequentOnSameLine) {
context.report({
node: node.test,
loc: {
start: firstTokenOfTest.loc.start,
end: lastTokenOfTest.loc.end
},
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;
}
});
}
if (!areConsequentAndAlternateOnSameLine) {
context.report({
node: node.consequent,
loc: {
start: firstTokenOfConsequent.loc.start,
end: lastTokenOfConsequent.loc.end
},
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 {
if (allowSingleLine && node.loc.start.line === node.loc.end.line) {
return;
}
if (areTestAndConsequentOnSameLine) {
context.report({
node: node.test,
loc: {
start: firstTokenOfTest.loc.start,
end: lastTokenOfTest.loc.end
},
messageId: "expectedTestCons",
fix: fixer => (hasComments ? null : (
fixer.replaceTextRange(
[
lastTokenOfTest.range[1],
questionToken.range[0]
],
"\n"
)
))
});
}
if (areConsequentAndAlternateOnSameLine) {
context.report({
node: node.consequent,
loc: {
start: firstTokenOfConsequent.loc.start,
end: lastTokenOfConsequent.loc.end
},
messageId: "expectedConsAlt",
fix: (fixer => (hasComments ? null : (
fixer.replaceTextRange(
[
lastTokenOfConsequent.range[1],
colonToken.range[0]
],
"\n"
)
)))
});
}
}
}
};
}
};