/** * @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-js', url: 'https://eslint.style/packages/js', }, rule: { name: 'multiline-ternary', url: 'https://eslint.style/rules/js/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' ) ), }); } } }, }; }, };