eslint-plugin-sonarjs
Version:
SonarJS rules for ESLint
93 lines (92 loc) • 3.89 kB
JavaScript
/*
* 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/S6594/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");
const extract_js_1 = require("../helpers/regex/extract.js");
exports.rule = {
meta: (0, index_js_1.generateMeta)(meta_js_1.meta, {
hasSuggestions: true,
messages: {
useExec: 'Use the "RegExp.exec()" method instead.',
suggestExec: 'Replace with "RegExp.exec()"',
},
}),
create(context) {
const services = context.sourceCode.parserServices;
if (!(0, index_js_1.isRequiredParserServices)(services)) {
return {};
}
return {
"CallExpression[arguments.length=1] > MemberExpression.callee[property.name='match'][computed=false]": (memberExpr) => {
const { object, property } = memberExpr;
if (!(0, index_js_1.isString)(object, services)) {
return;
}
const callExpr = memberExpr.parent;
const regex = (0, extract_js_1.getParsedRegex)(callExpr.arguments[0], context);
if (regex?.flags.global) {
return;
}
const variable = getLhsVariable(callExpr);
for (const ref of variable?.references ?? []) {
const id = ref.identifier;
const parent = (0, index_js_1.getNodeParent)(id);
if ((0, index_js_1.isMemberWithProperty)(parent, 'length')) {
return;
}
}
context.report({
node: property,
messageId: 'useExec',
suggest: [
{
messageId: 'suggestExec',
fix(fixer) {
const strText = context.sourceCode.getText(object);
const regText = context.sourceCode.getText(callExpr.arguments[0]);
const code = `RegExp(${regText}).exec(${strText})`;
return fixer.replaceText(callExpr, code);
},
},
],
});
},
};
/**
* Extracts the left-hand side variable of expressions
* like `x` in `const x = <node>` or `x` in `x = <node>`.
*/
function getLhsVariable(node) {
const parent = (0, index_js_1.getNodeParent)(node);
let ident;
if (parent.type === 'VariableDeclarator' && parent.id.type === 'Identifier') {
ident = parent.id;
}
else if (parent.type === 'AssignmentExpression' && parent.left.type === 'Identifier') {
ident = parent.left;
}
if (ident) {
return (0, index_js_1.getVariableFromName)(context, ident.name, node);
}
return null;
}
},
};
;