UNPKG

eslint-plugin-sonarjs

Version:
93 lines (92 loc) 3.86 kB
"use strict"; /* * SonarQube JavaScript Plugin * Copyright (C) 2011-2025 SonarSource SA * mailto:info AT sonarsource DOT com * * This program is free software; you can redistribute it and/or * modify it under the terms of the Sonar Source-Available License Version 1, as published by SonarSource SA. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the Sonar Source-Available License for more details. * * You should have received a copy of the Sonar Source-Available License * along with this program; if not, see https://sonarsource.com/license/ssal/ */ // https://sonarsource.github.io/rspec/#/rspec/S1110/javascript Object.defineProperty(exports, "__esModule", { value: true }); exports.rule = void 0; const index_js_1 = require("../helpers/index.js"); const meta_js_1 = require("./meta.js"); /** * Parts of the grammar that are required to have parentheses. */ const parenthesized = { DoWhileStatement: 'test', IfStatement: 'test', SwitchStatement: 'discriminant', WhileStatement: 'test', WithStatement: 'object', ArrowFunctionExpression: 'body', ImportExpression: 'source', }; exports.rule = { meta: (0, index_js_1.generateMeta)(meta_js_1.meta, { hasSuggestions: true }, true), create(context) { return { '*'(node) { checkRedundantParentheses(context.sourceCode, node, context); }, }; }, }; function checkRedundantParentheses(sourceCode, node, context) { const parenthesesPairsAroundNode = getParenthesesPairsAround(sourceCode, node, node); const parent = (0, index_js_1.getParent)(context, node); // Ignore parentheses pair from the parent node if (!!parent && isInParentNodeParentheses(node, parent)) { parenthesesPairsAroundNode.pop(); } // One pair of parentheses is allowed for readability purposes parenthesesPairsAroundNode.shift(); parenthesesPairsAroundNode.forEach(parentheses => { (0, index_js_1.report)(context, { message: `Remove these redundant parentheses.`, loc: parentheses.openingParenthesis.loc, suggest: [ { desc: 'Remove these redundant parentheses', fix(fixer) { return [ fixer.remove(parentheses.openingParenthesis), fixer.remove(parentheses.closingParenthesis), ]; }, }, ], }, [(0, index_js_1.toSecondaryLocation)(parentheses.closingParenthesis)]); }); } function getParenthesesPairsAround(sourceCode, start, end) { const tokenBefore = sourceCode.getTokenBefore(start); const tokenAfter = sourceCode.getTokenAfter(end); if (!!tokenBefore && !!tokenAfter && tokenBefore.value === '(' && tokenAfter.value === ')') { return [ { openingParenthesis: tokenBefore, closingParenthesis: tokenAfter }, ...getParenthesesPairsAround(sourceCode, tokenBefore, tokenAfter), ]; } return []; } function isInParentNodeParentheses(node, parent) { // Applying same logic as https://github.com/eslint/eslint/blob/main/lib/rules/no-sequences.js#L81 // both rules (S1110 and S878) can contradict each other, so better use the same logic const parentAttribute = parenthesized[parent.type]; const nodeIsInConditionOfParent = parentAttribute && node === parent[parentAttribute]; const nodeIsArgumentOfCallExpression = (parent.type === 'CallExpression' || parent.type === 'NewExpression') && parent.arguments.includes(node); return nodeIsInConditionOfParent || nodeIsArgumentOfCallExpression; }