You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

no-implicit-coercion.js 2.5KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. /*
  2. * SonarQube
  3. * Copyright (C) 2009-2023 SonarSource SA
  4. * mailto:info AT sonarsource DOT com
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 3 of the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public License
  17. * along with this program; if not, write to the Free Software Foundation,
  18. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  19. */
  20. module.exports = {
  21. meta: {
  22. type: 'suggestion',
  23. docs: {
  24. description:
  25. 'Enforce using explicit comparison instead of implicit coercion for certain variable types',
  26. category: 'Best Practices',
  27. recommended: true,
  28. },
  29. messages: {
  30. noImplicitCoercion:
  31. 'Use explicit comparison instead of implicit coercion for strings and numbers.',
  32. },
  33. },
  34. create(context) {
  35. return {
  36. UnaryExpression: (node) => {
  37. const { argument, operator } = node;
  38. if (operator === '!') {
  39. checkImplicitCoercion(context, argument);
  40. }
  41. },
  42. LogicalExpression: (node) => {
  43. const { left, operator } = node;
  44. if (operator === '??') {
  45. return;
  46. }
  47. if (isVariableOrObjectField(left)) {
  48. checkImplicitCoercion(context, left);
  49. }
  50. },
  51. IfStatement: (node) => {
  52. const { test } = node;
  53. checkImplicitCoercion(context, test);
  54. },
  55. };
  56. },
  57. };
  58. const isForbiddenType = (type) =>
  59. type.intrinsicName === 'number' || type.intrinsicName === 'string';
  60. const isVariableOrObjectField = (node) =>
  61. node.type === 'Identifier' || node.type === 'MemberExpression';
  62. function checkImplicitCoercion(context, argument) {
  63. const tsNodeMap = context.parserServices.esTreeNodeToTSNodeMap;
  64. const typeChecker = context.parserServices?.program?.getTypeChecker();
  65. const type = typeChecker.getTypeAtLocation(tsNodeMap.get(argument));
  66. if (type.aliasSymbol && type.aliasSymbol.name === 'ReactNode') {
  67. return;
  68. }
  69. if (type.isUnion() ? type.types.some(isForbiddenType) : isForbiddenType(type)) {
  70. context.report({
  71. node: argument,
  72. messageId: 'noImplicitCoercion',
  73. });
  74. }
  75. }