non-existent-operator.js 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. "use strict";
  2. /*
  3. * eslint-plugin-sonarjs
  4. * Copyright (C) 2018-2021 SonarSource SA
  5. * mailto:info AT sonarsource DOT com
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU Lesser General Public
  9. * License as published by the Free Software Foundation; either
  10. * version 3 of the License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public License
  18. * along with this program; if not, write to the Free Software Foundation,
  19. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  20. */
  21. // https://sonarsource.github.io/rspec/#/rspec/S2757
  22. const docs_url_1 = require("../utils/docs-url");
  23. const rule = {
  24. meta: {
  25. messages: {
  26. useExistingOperator: 'Was "{{operator}}=" meant instead?',
  27. suggestExistingOperator: 'Replace with "{{operator}}" operator',
  28. },
  29. schema: [],
  30. type: 'problem',
  31. hasSuggestions: true,
  32. docs: {
  33. description: 'Non-existent operators "=+", "=-" and "=!" should not be used',
  34. recommended: 'error',
  35. url: (0, docs_url_1.default)(__filename),
  36. },
  37. },
  38. create(context) {
  39. return {
  40. AssignmentExpression(node) {
  41. const assignmentExpression = node;
  42. if (assignmentExpression.operator === '=') {
  43. checkOperator(context, assignmentExpression.right);
  44. }
  45. },
  46. VariableDeclarator(node) {
  47. const variableDeclarator = node;
  48. checkOperator(context, variableDeclarator.init);
  49. },
  50. };
  51. },
  52. };
  53. function checkOperator(context, unaryNode) {
  54. var _a;
  55. if (unaryNode &&
  56. unaryNode.type === 'UnaryExpression' &&
  57. isUnaryOperatorOfInterest(unaryNode.operator)) {
  58. const sourceCode = context.getSourceCode();
  59. const assignmentOperatorToken = sourceCode.getTokenBefore(unaryNode, token => token.value === '=');
  60. const unaryOperatorToken = sourceCode.getFirstToken(unaryNode);
  61. const expressionFirstToken = sourceCode.getFirstToken(unaryNode.argument);
  62. if (assignmentOperatorToken != null &&
  63. unaryOperatorToken != null &&
  64. expressionFirstToken != null &&
  65. areAdjacent(assignmentOperatorToken, unaryOperatorToken) &&
  66. !areAdjacent(unaryOperatorToken, expressionFirstToken)) {
  67. const suggest = [];
  68. if (((_a = unaryNode.parent) === null || _a === void 0 ? void 0 : _a.type) === 'AssignmentExpression') {
  69. const range = [
  70. assignmentOperatorToken.range[0],
  71. unaryOperatorToken.range[1],
  72. ];
  73. const invertedOperators = unaryOperatorToken.value + assignmentOperatorToken.value;
  74. suggest.push({
  75. messageId: 'suggestExistingOperator',
  76. data: {
  77. operator: invertedOperators,
  78. },
  79. fix: fixer => fixer.replaceTextRange(range, invertedOperators),
  80. });
  81. }
  82. context.report({
  83. messageId: 'useExistingOperator',
  84. data: {
  85. operator: unaryNode.operator,
  86. },
  87. loc: { start: assignmentOperatorToken.loc.start, end: unaryOperatorToken.loc.end },
  88. suggest,
  89. });
  90. }
  91. }
  92. }
  93. function isUnaryOperatorOfInterest(operator) {
  94. return operator === '-' || operator === '+' || operator === '!';
  95. }
  96. function areAdjacent(first, second) {
  97. return (first.loc.end.column === second.loc.start.column && first.loc.end.line === second.loc.start.line);
  98. }
  99. module.exports = rule;
  100. //# sourceMappingURL=non-existent-operator.js.map