258 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			JavaScript
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			258 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			JavaScript
		
	
	
		
			Executable File
		
	
	
	
	
/**
 | 
						|
 * @fileoverview Enforce newlines between operands of ternary expressions
 | 
						|
 * @author Kai Cataldo
 | 
						|
 * @deprecated in ESLint v8.53.0
 | 
						|
 */
 | 
						|
 | 
						|
"use strict";
 | 
						|
 | 
						|
const astUtils = require("./utils/ast-utils");
 | 
						|
 | 
						|
//------------------------------------------------------------------------------
 | 
						|
// Rule Definition
 | 
						|
//------------------------------------------------------------------------------
 | 
						|
 | 
						|
/** @type {import('../types').Rule.RuleModule} */
 | 
						|
module.exports = {
 | 
						|
	meta: {
 | 
						|
		deprecated: {
 | 
						|
			message: "Formatting rules are being moved out of ESLint core.",
 | 
						|
			url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
 | 
						|
			deprecatedSince: "8.53.0",
 | 
						|
			availableUntil: "10.0.0",
 | 
						|
			replacedBy: [
 | 
						|
				{
 | 
						|
					message:
 | 
						|
						"ESLint Stylistic now maintains deprecated stylistic core rules.",
 | 
						|
					url: "https://eslint.style/guide/migration",
 | 
						|
					plugin: {
 | 
						|
						name: "@stylistic/eslint-plugin",
 | 
						|
						url: "https://eslint.style",
 | 
						|
					},
 | 
						|
					rule: {
 | 
						|
						name: "multiline-ternary",
 | 
						|
						url: "https://eslint.style/rules/multiline-ternary",
 | 
						|
					},
 | 
						|
				},
 | 
						|
			],
 | 
						|
		},
 | 
						|
		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",
 | 
						|
										),
 | 
						|
						});
 | 
						|
					}
 | 
						|
				}
 | 
						|
			},
 | 
						|
		};
 | 
						|
	},
 | 
						|
};
 |