diff --git a/packages/eslint-plugin/src/rules/no-unnecessary-template-expression.ts b/packages/eslint-plugin/src/rules/no-unnecessary-template-expression.ts index 1eb00c2872ba..90ad42fb0169 100644 --- a/packages/eslint-plugin/src/rules/no-unnecessary-template-expression.ts +++ b/packages/eslint-plugin/src/rules/no-unnecessary-template-expression.ts @@ -10,6 +10,8 @@ import { getParserServices, isTypeFlagSet, isUndefinedIdentifier, + nullThrows, + NullThrowsReasons, } from '../util'; import { rangeToLoc } from '../util/rangeToLoc'; @@ -92,6 +94,22 @@ export default createRule<[], MessageId>({ ); } + function hasCommentsBetweenQuasi( + startQuasi: TSESTree.TemplateElement, + endQuasi: TSESTree.TemplateElement, + ): boolean { + const startToken = nullThrows( + context.sourceCode.getTokenByRangeStart(startQuasi.range[0]), + NullThrowsReasons.MissingToken('`${', 'opening template literal'), + ); + const endToken = nullThrows( + context.sourceCode.getTokenByRangeStart(endQuasi.range[0]), + NullThrowsReasons.MissingToken('}', 'closing template literal'), + ); + + return context.sourceCode.commentsExistBetween(startToken, endToken); + } + return { TemplateLiteral(node: TSESTree.TemplateLiteral): void { if (node.parent.type === AST_NODE_TYPES.TaggedTemplateExpression) { @@ -106,6 +124,10 @@ export default createRule<[], MessageId>({ isUnderlyingTypeString(node.expressions[0]); if (hasSingleStringVariable) { + if (hasCommentsBetweenQuasi(node.quasis[0], node.quasis[1])) { + return; + } + context.report({ loc: rangeToLoc(context.sourceCode, [ node.expressions[0].range[0] - 2, @@ -132,7 +154,7 @@ export default createRule<[], MessageId>({ nextQuasi: node.quasis[index + 1], prevQuasi: node.quasis[index], })) - .filter(({ expression, nextQuasi }) => { + .filter(({ expression, nextQuasi, prevQuasi }) => { if ( isUndefinedIdentifier(expression) || isInfinityIdentifier(expression) || @@ -141,6 +163,11 @@ export default createRule<[], MessageId>({ return true; } + // allow expressions that include comments + if (hasCommentsBetweenQuasi(prevQuasi, nextQuasi)) { + return false; + } + if (isLiteral(expression)) { // allow trailing whitespace literal if (startsWithNewLine(nextQuasi.value.raw)) { diff --git a/packages/eslint-plugin/tests/rules/no-unnecessary-template-expression.test.ts b/packages/eslint-plugin/tests/rules/no-unnecessary-template-expression.test.ts index d178ddd95f6a..6043b2b8b50d 100644 --- a/packages/eslint-plugin/tests/rules/no-unnecessary-template-expression.test.ts +++ b/packages/eslint-plugin/tests/rules/no-unnecessary-template-expression.test.ts @@ -310,10 +310,6 @@ const invalidCases: readonly InvalidTestCase< }\`; `, errors: [ - { - line: 2, - messageId: 'noUnnecessaryTemplateExpression', - }, { column: 2, endColumn: 2, @@ -331,12 +327,18 @@ const invalidCases: readonly InvalidTestCase< ], output: [ ` -\`use\${ - \`less\` -}\`; +\`u\${ + // hopefully this comment is not needed. + 'se' + +}le\${ \`ss\` }\`; `, ` -\`useless\`; +\`u\${ + // hopefully this comment is not needed. + 'se' + +}less\`; `, ], }, @@ -1104,6 +1106,42 @@ this code has trailing whitespace: \${' '} \`trailing position interpolated empty string also makes whitespace clear \${''} \`; `, + ` +\` +\${/* intentional comment before */ 'bar'} +...\`; + `, + ` +\` +\${'bar' /* intentional comment after */} +...\`; + `, + ` +\` +\${/* intentional comment before */ 'bar' /* intentional comment after */} +...\`; + `, + ` +\`\${/* intentional before */ 'bar'}\`; + `, + ` +\`\${'bar' /* intentional comment after */}\`; + `, + ` +\`\${/* intentional comment before */ 'bar' /* intentional comment after */}\`; + `, + ` +\`\${ + // intentional comment before + 'bar' +}\`; + `, + ` +\`\${ + 'bar' + // intentional comment after +}\`; + `, ], invalid: [
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: