no-string-refs.js 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. /**
  2. * @fileoverview Prevent string definitions for references and prevent referencing this.refs
  3. * @author Tom Hastjarjanto
  4. */
  5. 'use strict';
  6. const componentUtil = require('../util/componentUtil');
  7. const docsUrl = require('../util/docsUrl');
  8. const report = require('../util/report');
  9. const testReactVersion = require('../util/version').testReactVersion;
  10. // ------------------------------------------------------------------------------
  11. // Rule Definition
  12. // ------------------------------------------------------------------------------
  13. const messages = {
  14. thisRefsDeprecated: 'Using this.refs is deprecated.',
  15. stringInRefDeprecated: 'Using string literals in ref attributes is deprecated.',
  16. };
  17. /** @type {import('eslint').Rule.RuleModule} */
  18. module.exports = {
  19. meta: {
  20. docs: {
  21. description: 'Disallow using string references',
  22. category: 'Best Practices',
  23. recommended: true,
  24. url: docsUrl('no-string-refs'),
  25. },
  26. messages,
  27. schema: [{
  28. type: 'object',
  29. properties: {
  30. noTemplateLiterals: {
  31. type: 'boolean',
  32. },
  33. },
  34. additionalProperties: false,
  35. }],
  36. },
  37. create(context) {
  38. const checkRefsUsage = testReactVersion(context, '< 18.3.0'); // `this.refs` is writable in React 18.3.0 and later, see https://github.com/facebook/react/pull/28867
  39. const detectTemplateLiterals = context.options[0] ? context.options[0].noTemplateLiterals : false;
  40. /**
  41. * Checks if we are using refs
  42. * @param {ASTNode} node The AST node being checked.
  43. * @returns {boolean} True if we are using refs, false if not.
  44. */
  45. function isRefsUsage(node) {
  46. return !!(
  47. (componentUtil.getParentES6Component(context, node) || componentUtil.getParentES5Component(context, node))
  48. && node.object.type === 'ThisExpression'
  49. && node.property.name === 'refs'
  50. );
  51. }
  52. /**
  53. * Checks if we are using a ref attribute
  54. * @param {ASTNode} node The AST node being checked.
  55. * @returns {boolean} True if we are using a ref attribute, false if not.
  56. */
  57. function isRefAttribute(node) {
  58. return node.type === 'JSXAttribute'
  59. && !!node.name
  60. && node.name.name === 'ref';
  61. }
  62. /**
  63. * Checks if a node contains a string value
  64. * @param {ASTNode} node The AST node being checked.
  65. * @returns {boolean} True if the node contains a string value, false if not.
  66. */
  67. function containsStringLiteral(node) {
  68. return !!node.value
  69. && node.value.type === 'Literal'
  70. && typeof node.value.value === 'string';
  71. }
  72. /**
  73. * Checks if a node contains a string value within a jsx expression
  74. * @param {ASTNode} node The AST node being checked.
  75. * @returns {boolean} True if the node contains a string value within a jsx expression, false if not.
  76. */
  77. function containsStringExpressionContainer(node) {
  78. return !!node.value
  79. && node.value.type === 'JSXExpressionContainer'
  80. && node.value.expression
  81. && ((node.value.expression.type === 'Literal' && typeof node.value.expression.value === 'string')
  82. || (node.value.expression.type === 'TemplateLiteral' && detectTemplateLiterals));
  83. }
  84. return {
  85. MemberExpression(node) {
  86. if (checkRefsUsage && isRefsUsage(node)) {
  87. report(context, messages.thisRefsDeprecated, 'thisRefsDeprecated', {
  88. node,
  89. });
  90. }
  91. },
  92. JSXAttribute(node) {
  93. if (
  94. isRefAttribute(node)
  95. && (containsStringLiteral(node) || containsStringExpressionContainer(node))
  96. ) {
  97. report(context, messages.stringInRefDeprecated, 'stringInRefDeprecated', {
  98. node,
  99. });
  100. }
  101. },
  102. };
  103. },
  104. };