UNPKG

eslint-plugin-sonarjs

Version:
106 lines (105 loc) 4.6 kB
"use strict"; /* * SonarQube JavaScript Plugin * Copyright (C) 2011-2024 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 GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * 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 GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ // https://sonarsource.github.io/rspec/#/rspec/S1186/javascript Object.defineProperty(exports, "__esModule", { value: true }); exports.reportWithQuickFixIfApplicable = exports.decorate = void 0; const helpers_1 = require("../helpers"); const meta_1 = require("./meta"); function isRuleFunctionNode(node) { return (0, helpers_1.isFunctionNode)(node) && 'parent' in node; } // core implementation of this rule does not provide quick fixes function decorate(rule) { return (0, helpers_1.interceptReport)({ ...rule, meta: (0, helpers_1.generateMeta)(meta_1.meta, { ...rule.meta, hasSuggestions: true, }), }, reportWithQuickFixIfApplicable); } exports.decorate = decorate; function reportWithQuickFixIfApplicable(context, reportDescriptor) { if (!('node' in reportDescriptor) || !isRuleFunctionNode(reportDescriptor.node)) { return; } const functionNode = reportDescriptor.node; if (isApplicable(functionNode)) { reportWithQuickFix(context, reportDescriptor, functionNode); } } exports.reportWithQuickFixIfApplicable = reportWithQuickFixIfApplicable; // This function limits the issues to variable/function/method declarations which name is not like /^on[A-Z]. // Any lambda expression or arrow function is thus ignored. function isApplicable(functionNode) { // Matches identifiers like onClick and more generally onXxx as well as XXXnoopXXX functions function isExceptionalName(node) { return (node !== null && (0, helpers_1.isIdentifier)(node) && (/^on[A-Z]/.test(node.name) || /noop/i.test(node.name))); } // Matches: function foo() {} // But not: function onClose() {} or function XXXnoopXXX() {} function isFunctionDeclaration() { return functionNode.type === 'FunctionDeclaration' && !isExceptionalName(functionNode.id); } // Matches: class A { foo() {} } // But not: class A { onClose() {} } function isMethodDefinition() { const methodNode = functionNode.parent; return (methodNode.type === 'MethodDefinition' && methodNode.value === functionNode && !isExceptionalName(methodNode.key)); } // Matches: const foo = () => {}; // But not: const onClose = () => {}; function isVariableDeclarator() { const variableNode = functionNode.parent; return (variableNode.type === 'VariableDeclarator' && variableNode.init === functionNode && !isExceptionalName(variableNode.id)); } return isFunctionDeclaration() || isMethodDefinition() || isVariableDeclarator(); } function reportWithQuickFix(context, reportDescriptor, func) { const name = reportDescriptor.data.name; const openingBrace = context.sourceCode.getFirstToken(func.body); const closingBrace = context.sourceCode.getLastToken(func.body); suggestEmptyBlockQuickFix(context, reportDescriptor, name, openingBrace, closingBrace); } function suggestEmptyBlockQuickFix(context, descriptor, blockType, openingBrace, closingBrace) { let commentPlaceholder; if (openingBrace.loc.start.line === closingBrace.loc.start.line) { commentPlaceholder = ` /* TODO document why this ${blockType} is empty */ `; } else { const columnOffset = closingBrace.loc.start.column; const padding = ' '.repeat(columnOffset); commentPlaceholder = `\n${padding} // TODO document why this ${blockType} is empty\n${padding}`; } context.report({ ...descriptor, suggest: [ { desc: 'Insert placeholder comment', fix: fixer => fixer.insertTextAfter(openingBrace, commentPlaceholder), }, ], }); }